C 链表生成分割错误

C 链表生成分割错误,c,debugging,segmentation-fault,C,Debugging,Segmentation Fault,下面我用C语言制作了一个简单的链表。代码目前产生了一个分段错误,我觉得这很奇怪,因为我从我们当前的书中复制了一个例子。我对代码所做的唯一一件事就是将代码放入方法“addToList”中。我知道分割错误来自方法addToList,但我不知道我在哪里出错 #include <stdio.h> #include <stdlib.h> typedef struct node { int val; struct node *next; } Node; void addTo

下面我用C语言制作了一个简单的链表。代码目前产生了一个分段错误,我觉得这很奇怪,因为我从我们当前的书中复制了一个例子。我对代码所做的唯一一件事就是将代码放入方法“addToList”中。我知道分割错误来自方法addToList,但我不知道我在哪里出错

#include <stdio.h>
#include <stdlib.h>
typedef struct node {
  int val;
  struct node *next;
} Node;

void addToList(Node *, int);
void printList(Node *);

void main() {
  int x;
  Node *head = malloc(sizeof(Node));
  for (x = 1; x < 4); x++) {
    printf("Enter an integer: ");
    x = scanf("%d");
    addToList(head, x);
  }
  printList(head);
}

void addToList(Node *head, int val) {
  Node *current = head;

  while (current->next != NULL) {
    current = current->next;
  }

  current->next = malloc(sizeof(Node));
  current->next->val = val;
  current->next->next = NULL;
}

void printList(Node *head) {
  Node *current = head;

  while (current != NULL) {
    printf("%d->", current->val);
    current = current->next;
  }
  printf("\n");
}
#包括
#包括
类型定义结构节点{
int-val;
结构节点*下一步;
}节点;
void addToList(节点*,int);
作废打印列表(节点*);
void main(){
int x;
Node*head=malloc(sizeof(Node));
对于(x=1;x<4);x++){
printf(“输入一个整数:”);
x=扫描频率(“%d”);
地址列表(头,x);
}
印刷品清单(标题);
}
void addToList(节点*头,int val){
节点*电流=头部;
while(当前->下一步!=NULL){
当前=当前->下一步;
}
当前->下一步=malloc(sizeof(Node));
当前->下一步->val=val;
当前->下一步->下一步=空;
}
无效打印列表(节点*头){
节点*电流=头部;
while(当前!=NULL){
printf(“%d->”,当前->值);
当前=当前->下一步;
}
printf(“\n”);
}

如果您能告诉我哪里出了问题或哪里出了错,我们将不胜感激。

请仔细查看您的代码:

int main(void) {
  int x;
  Node *head = malloc(sizeof(Node));
  for (x = 1; x < 4); x++) {
      ...
    addToList(head, x);
  }
  ...
}
将循环未定义的次数。第一个
当前->下一个
是最
可能不是
NULL
,因此执行
current=current->next
。此时,
current
没有指向任何地方,因此未定义的行为在您的情况下会导致segfault

必须按如下方式初始化内存:

Node *head = malloc(sizeof *head);
if(head == NULL)
    // error handling

head->next = NULL;
但是您也可以使用
calloc
,这也会将内存设置为0,因此您不必初始化值(在本例中):

您应该始终检查
malloc
/
calloc
/
realloc
的返回值

还要注意,
main
函数的签名可以是以下之一:

  • int main(无效)
  • intmain(intargc,char**argv)
  • intmain(intargc,char*argv[])
编辑

我现在注意到的另一个错误是:

x = scanf("%d");
这不是工作原理。您必须传递一个指针,
scanf
保存 通过传递的指针扫描值
scanf
返回匹配的 成功的价值观,在这种情况下,成功是1:

int num;
int ret = scanf("%d", &num);
if(ret != 1)
{
    fprintf(stderr, "Could not read value from the user\n");
    continue; // to contiune looping

    // you could also do a break; and stop the looping, or
    // exit(1), etc.
}
    // error with scanf
对于循环迭代和用户输入,也不要使用相同的变量
x
, 否则,您将搞乱循环

编辑

用户user3629249在评论中写道


好的信息,但是结果将是链表中的第一个条目将包含垃圾。 最好通过以下方式声明头部:
节点*head=NULL
;函数
addToList()
检查是否为NULL并相应地继续

没错,
head
元素不会以这种方式保存任何数字

选项1:双指针

此处
addToList
接收一个双指针。
head
的初始化发生 当
*head
指向
NULL
时。函数为它分配内存,初始化 内存,保存值并返回。在
addToList的并发调用中
*head
不会为
NULL
,因此
addToList
会查找列表的末尾

我对您执行
malloc
realloc
的方式做了一些小的更改。我还补充说
freeList
的一种实现,用于释放内存:

void addToList(Node **head, int val) {
    if(head == NULL)
    {
        fprintf(stderr, "head cannot be NULL\n");
        return;
    }


    if(*head == NULL)
    {
        *head = calloc(1, sizeof **head);
        head[0]->val = val;
        head[0]->next = NULL;
        return;
    }
    Node *current = *head;

    while (current->next != NULL) {
        current = current->next;
    }

    current->next = malloc(sizeof *current->next);
    if(current->next == NULL)
        return;
    current->next->val = val;
    current->next->next = NULL;
}

int main(void)
{
    int x;
    Node *head = NULL;
    for (x = 1; x < 4; x++)
    {
        int val;
        printf("Enter an integer: ");
        if(scanf("%d", &val) != 1)
        {
            fprintf(stderr, "Could not read from user. Skipping entry\n");
            continue;
        }

        addToList(&head, val);
    }

    printList(head);

    freeList(head);
    return 0;
}

void freeList(Node *head)
{
    if(head == NULL)
        return;

    Node *current = head;
    Node *next;

    while(next = current->next)
    {
        free(current);
        current = next;
    }

    free(current); // the last one

    free(head);
}

请仔细查看您的代码:

int main(void) {
  int x;
  Node *head = malloc(sizeof(Node));
  for (x = 1; x < 4); x++) {
      ...
    addToList(head, x);
  }
  ...
}
将循环未定义的次数。第一个
当前->下一个
是最
可能不是
NULL
,因此执行
current=current->next
。此时,
current
没有指向任何地方,因此未定义的行为在您的情况下会导致segfault

必须按如下方式初始化内存:

Node *head = malloc(sizeof *head);
if(head == NULL)
    // error handling

head->next = NULL;
但是您也可以使用
calloc
,这也会将内存设置为0,因此您不必初始化值(在本例中):

您应该始终检查
malloc
/
calloc
/
realloc
的返回值

还要注意,
main
函数的签名可以是以下之一:

  • int main(无效)
  • intmain(intargc,char**argv)
  • intmain(intargc,char*argv[])
编辑

我现在注意到的另一个错误是:

x = scanf("%d");
这不是工作原理。您必须传递一个指针,
scanf
保存 通过传递的指针扫描值
scanf
返回匹配的 成功的价值观,在这种情况下,成功是1:

int num;
int ret = scanf("%d", &num);
if(ret != 1)
{
    fprintf(stderr, "Could not read value from the user\n");
    continue; // to contiune looping

    // you could also do a break; and stop the looping, or
    // exit(1), etc.
}
    // error with scanf
对于循环迭代和用户输入,也不要使用相同的变量
x
, 否则,您将搞乱循环

编辑

用户user3629249在评论中写道


好的信息,但是结果将是链表中的第一个条目将包含垃圾。 最好通过以下方式声明头部:
节点*head=NULL
;函数
addToList()
检查是否为NULL并相应地继续

没错,
head
元素不会以这种方式保存任何数字

选项1:双指针

此处
addToList
接收一个双指针。
head
的初始化发生 当
*head
指向
NULL
时。函数为它分配内存,初始化 内存,保存值并返回。在
addToList的并发调用中
*head
不会为
NULL
,因此
addToList
会查找列表的末尾

我对您执行
malloc
realloc
的方式做了一些小的更改。我还补充说