我的链表每次都会导致分段错误,即使我看不到缺陷

My linked list results in segmentation fault every time even though I cannot see a flaw

我学习编程已经有一段时间了,我已经看过几次“链表”的概念并决定尝试一下:

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

typedef struct cell {
    int number;
    struct cell* next;
} cell;

typedef struct {
    cell* head;
} cell_list;


void push_front(cell_list* list, int number) {
    printf("here\n");
    cell* n;
    printf("here2\n");
    n->number = number;
    printf("here3\n");
    n->next = list->head;
    printf("here4\n");
    list->head = n;
}

int main(int argc, char* argv[]) {
    cell_list* L;

    push_front(L, 5);
    push_front(L, 8);
    push_front(L, 19);

    cell* n = L->head;

    // this should print "19 8 5"
    while(n != NULL) {
        printf("Val: %d\n", n->number);
        n = n->next;
    }

    return 0;
}

输出:

here
here2
here3
Segmentation fault: 11

我正在寻找以下两个问题的答案: (1) 这样做的正确方法是什么 (2) 我的示例中实际发生了什么?出了什么问题?

我认为是编译器未能将“struct cell* next”分配为等于“cell* head”等)或者第一个为 head 和第一个单元格分配的内存next 属性 这里有问题。

也有类似的 posts 和问题对与我相同的问题有答案,但它们在多个方面都失败了: (1) OP posted 的代码示例过于复杂 (2) 代码答案很好但是...检查 3 (3) 代码回答但没有解释,只是“我的天啊,只要使用 malloc 你到处都是空洞” (4) 1 - 3 的结果是一个完整的 post 与 Q&A 高于我的水平。如果您的答案是“使用 malloc”或“指针指向随机内存”或“您指向 null”。请解释一下,因为这些只是编程 jargon/language 的句子,实际上并没有深入到我这个初学者可以理解的地方。

我完全知道有相同的 post 但 none 真正向像我这样的初学者解释了为什么他们分配内存将 malloc 并将分配的 space 转换为链接列表结构。如果你的答案与那些 post 中的任何一个相同,那么请解释为什么这种方式是错误的,而不仅仅是“你就是这样做的,关于 malloc 和链表有 12893 posts ”我理解 malloc 和转换,如果这不是很明显的话,但不知道它们如何适合这里以及我当前的程序是如何在堆栈上创建的。

函数中push_front,

cell* n;

是一个 cell 类型的指针,正如 David C Rankin 所说的那样,它是未初始化的,并且当前持有一个不确定的地址作为它的值,直到你通过分配一个有效地址来初始化它。它不会像那样指向 cell 类型的内存,直到您将其指向 cell 类型。

使用malloc分配内存。您可以参考 malloc.

的手册页
cell *n= malloc(sizeof(cell));

您的代码接下来应该做的是检查对 malloc 的调用是否已成功分配内存,如果未分配内存则进行一些错误处理。

if(NULL == n)
{
    //! handle memory allocation error here
}

您还需要在使用完毕后释放此内存,并使指针指向 null。

free(n);
n = NULL;

根据你在原文末尾的批评rant/comment post,让我解释一下你写给你的代码。

void push_front(cell_list* list, int number)
{
    /// This print helps you understand where the code is.
    printf("here\n");
    /// This declares is a pointer variable pointing to a `cell` type. 
    /// Not yet pointing since not initialized.
    cell* n;
    /// This print helps you understand where the code is.
    printf("here2\n");
    /// Tries to assign value of 'number' to 'number' variable present in 
    /// some memory accessed as data type `cell` via a pointer. 
    /// But wait, is pointer really pointing to a valid memory location 
    /// that can be access as `cell` type? NO!
    n->number = number; // You try to sit in a chair which isn't there, you fall!
    printf("here3\n");
    n->next = list->head; // You try to sit on a chair which isn't there, you fall!
    printf("here4\n");
    list->head = n; // This is a different problem as of now. 
                    // With 'n' not initialized, list->head also get
                    // corrupted since assigned with a garbage value. 
}

此外,在您的 main() 函数中,

cell_list* L;

然后你调用

push_front(L, 5);

在此函数中,您执行以下操作:

n->next = list->head;

你的设计没有考虑list->head有没有初始化。如果它是 NULL 你只是让 n->next 指向 NULL。

我理解并同意很多人发现指针难以正确理解和使用这一事实。我建议您首先(总体上)熟悉指针,然后再用它们实现数据结构。我们都从那里开始!你可以开始 .

您必须使用 malloc 为节点分配内存。 这是更新后的代码,我已经测试过了,它工作正常:)

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

typedef struct cell {
    int number;
    struct cell* next;
} cell;

typedef struct {
    cell* head;
} cell_list;


void push_front(cell_list* list, int number) {
    printf("here\n");
    cell* n = malloc(sizeof(cell));
    printf("here2\n");
    n->number = number;
    printf("here3\n");
    n->next = list->head;
    printf("here4\n");
    list->head = n;
}

int main(int argc, char* argv[]) {
    cell_list* L = malloc(sizeof(cell_list));

    push_front(L, 5);
    push_front(L, 8);
    push_front(L, 19);

    cell* n = L->head;

    // this should print "19 8 5"
    while(n != NULL) {
        printf("Val: %d\n", n->number);
        n = n->next;
    }

    return 0;
}