简体   繁体   English

链表分割错误

[英]Linked List making segmentation fault

Below I have made a simple Linked List in C. The code is currently producing a segmentation fault which I find odd because I was copying an example from our current book. 下面,我在C语言中创建了一个简单的链表。该代码当前正在产生一个分段错误,由于我要从当前书中复制一个示例,因此我觉得很奇怪。 The only thing I did to the code was put the code into the method "addToList". 我对代码所做的唯一一件事就是将代码放入“ addToList”方法中。 I'm aware the segmentation fault is coming from the method addToList but I do not know where I made a mistake. 我知道细分错误来自方法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");
}

Any help with telling me what is wrong or where I'm making the mistake would be greatly appreciated. 如有任何关于告诉我什么地方出了问题或在哪里犯错的帮助,将不胜感激。

Look carefully at your code: 仔细看看您的代码:

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

You are not initializing the memory, so head->val and head->next are not initialized. 您没有初始化内存,因此head->valhead->next未初始化。 Because of that 因此

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

will loop an undefined amount of times. 将循环不确定的时间。 The first current->next is most probably not NULL , so current = current->next get executed. 第一个current->next很可能不是NULL ,因此current = current->next会被执行。 At that point current is pointing to nowhere, hence the undefined behaviour which in your case leads to a segfault. 此时, current指向无处,因此未定义的行为会导致段错误。

You have to initialized the memory like this: 您必须像这样初始化内存:

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

head->next = NULL;

But you could also use calloc , which also sets the memory to 0, thus you don't have to initialize the values (in this case): 但是您也可以使用calloc ,它将内存设置为0,因此不必初始化值(在这种情况下):

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

You should always check for the return value of malloc / calloc / realloc . 您应该始终检查malloc / calloc / realloc的返回值。

Also note that the signature of the main function can be one of these: 另请注意, main函数的签名可以是以下之一:

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

edit 编辑

Another error I've noticed right now: 我现在注意到的另一个错误:

x = scanf("%d");

That's not how scanf works. 那不是scanf工作方式。 You have to pass a pointer, scanf saves the scanned value through the passed pointer. 您必须传递一个指针, scanf通过传递的指针保存扫描的值。 scanf returns the number of matched values on success, in this case, success would be 1: 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

Also don't use the same variable x for the loop iteration and user input, otherwise you are messing with the loop. 另外,不要在循环迭代和用户输入中使用相同的变量x ,否则会弄乱循环。

edit 编辑

User user3629249 wrote in the comment 用户user3629249在评论中写道

good information, however the result will be the first entry in the linked list will contain garbage. 好信息,但是结果将是链接列表中的第一个条目将包含垃圾。 Better to declare head via: Node *head = NULL ; 最好通过以下方式声明head: Node *head = NULL and the function addToList() check for NULL and proceed accordingly. 然后函数addToList()检查是否为NULL并继续进行相应的操作。

That's right, the head element doesn't save any number in this way. 没错, head元素不会以这种方式保存任何数字。

Option 1: double pointer 选项1:双指针

Here addToList receives a double pointer. 在这里, addToList接收一个双指针。 The initialization of head occurs when *head points to NULL . 初始化head时发生*head指向NULL The function allocates memory for it, initializes the memory, saves the value and returns. 该函数为其分配内存,初始化内存,保存值并返回。 In the concurrent calls of addToList *head won't be NULL , so addToList looks for the end of the list. addToList的并发调用中, *head不会为NULL ,因此addToList查找列表的末尾。

I've made small changes in the way you do malloc and realloc . 我对mallocrealloc的方式做了一些小的更改。 Also I added an implementation of freeList which should be used to free the memory: 我还添加了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);
}

Option 2: addToList returns a pointer to the head 选项2: addToList返回指向头的指针

Here addToList takes a pointer to the head. 在这里, addToList指向头部。 If it's NULL , it allocates memory and initializes like in the shown above. 如果为NULL ,它将分配内存并进行初始化,如上所示。 If head is not NULL , the functions looks for the last element and the returns the head . 如果head不为NULL ,则函数将查找最后一个元素并返回head On error the function returns NULL . 错误时,函数返回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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM