链接列表使分段错误

时间:2018-01-19 01:17:51

标签: c debugging segmentation-fault

下面我在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");
}

任何帮助告诉我什么是错的或者我犯错的地方都会非常感激。

1 个答案:

答案 0 :(得分:3)

仔细查看您的代码:

int main(void) {
  int x;
  Node *head = malloc(sizeof(Node));
  for (x = 1; x < 4); x++) {
      ...
    addToList(head, x);
  }
  ...
}

您没有初始化内存,因此head->valhead->next不是 初始化。因为那个

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

将循环不确定的次数。第一个current->next是最多的 可能不是NULL,所以current = current->next会被执行。此时current指向无处,因此未定义的行为在您的情况下会导致段错误。

你必须像这样初始化内存:

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

head->next = NULL;

但你也可以使用calloc,它也将内存设置为0,因此你不必初始化值(在这种情况下):

Node *head = calloc(1, sizeof *head);
if(head == NULL)
    // error handling

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

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

  • int main(void);
  • int main(int argc, char **argv);
  • int main(int argc, char *argv[]);

修改

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

x = scanf("%d");

这不是scanf的工作方式。你必须传递一个指针,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在评论中写道

     

良好的信息,但结果将是链表中的第一个条目将包含垃圾。   最好通过以下方式宣布:Node *head = NULL;并且函数addToList()检查NULL并相应地继续。

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

选项1:双指针

这里addToList收到一个双指针。 head的初始化发生 当*head指向NULL时。该函数为其分配内存,进行初始化 记忆,保存价值和回报。在addToList的并发调用中 *head不会是NULL,因此addToList会查找列表的结尾。

我对mallocrealloc的方式做了一些小改动。我还补充说 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);
}

选项2:addToList返回指向头部的指针

这里addToList指向头部。如果是NULL,则分配 内存和初始化如上所示。如果head不是NULL,那么。{ 函数查找最后一个元素,并返回head。出错了 函数返回NULL

Node *addToList(Node *head, int val) {

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

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

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

    return head;
}

int main(void)
{
    int x;
    Node *head = NULL, *tmp;
    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;
        }

        tmp = addToList(head, val);
        if(tmp == NULL)
        {
            fprintf(stderr, "Not enough memory\n");
            freeList(head);
            return 1;
        }

        head = tmp;

    }

    printList(head);

    freeList(head);
    return 0;
}