首页 > 解决方案 > 即使我看不到缺陷,我的链表每次都会导致分段错误

问题描述

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

#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 属性的单元有问题这里。

类似的帖子和问题也有与我相同的问题的答案,但是它们在多个方面都失败了:(1)OP 发布的代码示例过于复杂(2)代码答案很好但是......检查 3(3)代码答案而不是解释,只是“天哪,只要使用 malloc,你就在各处铸造空隙”(4) 1 - 3 会导致一个完整的帖子,其中包含高于我水平的问答。如果您的答案是“使用 malloc”或“指针指向随机内存”或“您指向 null”。请解释一下,因为这些只是编程术语/语言句子,实际上并没有深入,所以我,一个初学者,可以理解。

我完全知道有相同的帖子,但没有人真正向像我这样的初学者解释为什么他们分配内存会 malloc 并将分配的空间转换为链表结构。如果您的答案与这些帖子中的任何一个相同,那么请解释为什么这种方式是错误的,而不仅仅是“这就是您的做法,有 12893 篇关于 malloc 和链表的帖子。” 我了解 malloc 和强制转换,如果这不是很明显,但不知道它们如何正确地适合这里以及我当前的程序是如何在堆栈上创建的。

标签: clinked-listsegmentation-fault

解决方案


在函数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;

根据您在原始帖子末尾的批评/评论,让我解释一下您写给您的代码。

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。

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


推荐阅读