尝试将节点插入链表时出现分段错误

Segmentation fault while trying to insert node into a linked list

几天前,我通过《C 语言编程》这本书开始学习 C 编程,并且对 java 有一定的了解。在 java 中将节点插入链表非常容易,但我想我是否可以在 C 中做同样的事情。 所以,我想出了这个程序,

#include "node.h"

void insertEntry(struct node* root, struct node* after)
{
    struct node* first = root;
    while(first != (struct node*) 0)
    {
        if(first->value == after->value)
        {
            struct node ins;
            ins.value = 3456;
            ins.next = first->next;
            first->next = &ins;
        }
        first = first->next;
    }
}

int main(void)
{
    struct node n1, n2, n3;
    struct node* list_pointer = &n1;

    n1.value = 100;
    n1.next = &n2;

    n2.value = 200;
    n2.next = &n3;

    n3.value = 300;
    n3.next = (struct node*) 0;

    void insertEntry(struct node* root, struct node* after);

    while (list_pointer != (struct node*) 0)
    {
        printf("%i\n", list_pointer->value);
        list_pointer = list_pointer->next;
    }
    printf("\n");

    list_pointer = &n1;

    insertEntry(list_pointer, &n2);

    while (list_pointer != (struct node*) 0)
    {
        printf("%i\n", list_pointer->value);
        list_pointer = list_pointer->next;
    }

    return 0;
}

node.h

#include <stdio.h>

struct node
{
    int value;
    struct node* next;
};

基本上,这个程序采用指向链表第一个元素的指针和指向要插入的元素的指针,并在该节点之后插入一个新节点。

但是,当我 运行 执行此操作时,我的程序崩溃了,而且我找不到发生此错误的位置或原因。 我查看了 java 中的代码并尝试在 C 中实现相同的代码。

谢谢。

这是你的问题:

    {
        struct node ins;  // You create an object in the stack
        ins.value = 3456;
        ins.next = first->next;
        first->next = &ins;   // You reference your object
    }  // Your object is popped out of the stack and ceases to exist
    // Any access to first->next past this block may cause segfault

为了避免这种情况,您可以使用 malloc() 创建 ins,但请注意:这不是 java 并且您必须跟踪您分配的所有对象自己堆。

您应该阅读 gdb 及其使用方法。

gcc -Wall -O0 -g x.c -o x 

x 是你编译的程序,带有调试信息,没有优化。

然后运行你的程序通过gdb找到了location/occurrence的错。 即

gdb x 

主要问题是您插入一个在堆栈上分配的节点——一旦函数离开,它就无效了。要分配新内存,你需要malloc()(完成后不要忘记free(),没有垃圾collection)。

一些旁注:

  • 当用作指向任何特定指针类型的指针时,转换 0 是完全没有意义的……0 是 0。

  • 插入不需要根节点,为什么要先传?

  • 在函数内部声明一个原型(在那种情况下:main)没有太大意义......它会在没有的情况下工作,因为你想调用的函数已经在同一个文件。

  • #includeheaders需要的地方! node.h不需要stdio,主程序需要。

大致可以运行的程序版本:

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

struct node
{
    int value;
    struct node *next;
};

struct node *insertEntry(struct node* after, int val)
{
    assert(after); /* not NULL */

    struct node *new = malloc(sizeof(struct node));
    new->value = val;
    new->next = after->next;
    after->next = new;
    return new;
}

void freeNodeList(struct node* root)
{
    struct node *current, *last;

    current = root;

    while (current)
    {
        last = current;
        current = current->next;
        free(last);
    }
}

int main(void)
{
    struct node *n1, *n2, *n3;
    struct node *ptr;

    n1 = malloc(sizeof(struct node));
    n2 = malloc(sizeof(struct node));
    n3 = malloc(sizeof(struct node));

    n1->value = 100;
    n1->next = n2;

    n2->value = 200;
    n2->next = n3;

    n3->value = 300;
    n3->next = 0;

    insertEntry(n2, 250);

    ptr = n1;
    while (ptr)
    {
        printf("%d\n", ptr->value);
        ptr = ptr->next;
    }

    freeNodeList(n1);
    return 0;
}