使用 C 的链表分段错误

Segmentation Fault on Linked List Using C

初学C,想学习一下C在链表上的实现。我真的很困惑为什么我不能在 main 函数中访问 myList?因为当我尝试 myList->data 时,这是分段错误。我认为我的 addtohead 函数有一些错误? 下面是我的代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct NODE{
    int data;
    struct NODE *next;
}node;

node * myList;

node * addToHead(node*, int);
void printList();

int main(){
    myList = NULL;
    int input;
    while (scanf("%i",&input) == 1){
           addToHead(myList, input);
           printf("%d \n", myList->data);
       }

    printf("My List:\n");
    printList(myList);
    return 0;
}

node* addToHead(node* head, int newData){
    node *temp = (node *)malloc(sizeof(node));
    temp -> data = newData;
    temp -> next = NULL;
    if(head != NULL){
        temp -> next = head;
        }
    head = temp;
    return head;
}

void printList(node* head){
    node *temp = head;
    while(temp != NULL){
        printf("%d ", temp->data);
        temp = temp -> next;
    }
    printf("\n");
}

您 return 来自 addToHead 的新头节点,但您不对其进行任何操作。您需要将此值分配给 myList 才能更新它:

myList = addToHead(myList, input);

此外,您在以下行中拼错了一个变量:

printf("%d \n", myListd->data);

应该是:

printf("%d \n", myList->data);

您的 addToHead 函数应该 return mallocated 内存返回给调用者。

所以你应该先把return值赋给mylist:

int main(){
    node *myList = NULL;
    int input;
    while (scanf("%i",&input) == 1){
           myList = addToHead(myList, input);
           printf("%d \n", myList->data);
       }

    printf("My List:\n");
    printList(myList);
    return 0;
}

进入您编写的 addToHead 函数

head = temp;

但是 head 具有局部作用域,分配的值不会反映到指针 myList

为此,您必须使用指向指针的指针。

int main(){
    node *myList = NULL;
    int input;
    while (scanf("%i",&input) == 1)
    {
       if (addToHead(&myList, input) == true)
       {
           printf("%d \n", myList->data);
       }
       else
       {
           fprintf(stderr, "Error addToHead\n");
       }
    }

    return 0;
}

bool addToHead(node** head, int newData){
    node *temp = malloc(sizeof(node));
    if (temp != NULL)
    {
       temp -> data = newData;
       temp -> next = NULL;
       if(head != NULL)
       {
          temp -> next = *head;
       }

       *head = temp;

       return true;
   }

   return false;
}

最后 永远记得检查 malloc return 值:它可能会失败。

在这个函数定义中

node* addToHead(node* head, int newData){
    node *temp = (node *)malloc(sizeof(node));
    temp -> data = newData;
    temp -> next = NULL;
    if(head != NULL){
        temp -> next = head;
        }
    head = temp;
    return head;
}

参数node* head是函数的局部变量。参数的任何更改都不会影响原始参数。函数参数在函数退出后会被销毁

你可以考虑函数定义和调用方式如下

addToHead(myList, input);
//...
node* addToHead(/*node* head, int newData*/){
    node *head = myList;
    int newData = input;

    node *temp = (node *)malloc(sizeof(node));
    temp -> data = newData;
    temp -> next = NULL;
    if(head != NULL){
        temp -> next = head;
        }
    head = temp;
    return head;
}

所以函数调用后原变量myList不会改变。您必须将返回值显式分配给变量

myList = addToHead(myList, input);

该功能也有缺点。如果没有分配新节点,它不会报告错误。

编写函数的更好方法如下所示

int /* _Bool */ addToHead( node **head, int newData )
{
    node *temp = ( node * )malloc( sizeof( node ) );
    int /* _Bool */ success = temp != NULL;

    if ( success )
    {
        temp -> data = newData;
        temp -> next = *head;
        *head = temp;
    }

    return success;
}

在这种情况下,可以通过以下方式在循环中调用该函数

while ( scanf( "%i", &input ) == 1 && addToHead( &myList, input ) )
{
    //...
}