C 在linkedlist中追加节点-为什么分段错误?

C 在linkedlist中追加节点-为什么分段错误?,c,pointers,linked-list,malloc,C,Pointers,Linked List,Malloc,我正在用C语言实现一个链表 struct node { int data; struct node *next; }; 我编写了append函数在链表末尾添加一个节点,如下所示,display函数显示所有节点。但我认为,由于append函数中的一些不一致性,display给出了分段错误。这里有什么问题?我的书使用malloc为append提供了类似的函数。我想知道我的功能出了什么问题 void append(struct node **q, int d) { struc

我正在用C语言实现一个链表

struct node
{
    int data;
    struct node *next;
};
我编写了append函数在链表末尾添加一个节点,如下所示,display函数显示所有节点。但我认为,由于append函数中的一些不一致性,display给出了分段错误。这里有什么问题?我的书使用malloc为append提供了类似的函数。我想知道我的功能出了什么问题

void append(struct node **q, int d)
{
    struct node *temp;
    temp = *q;
    printf("\nBegin: Address at temp = %u", temp);
    while (temp!= NULL){
        temp = temp->next;
        printf("\nTravel: Address at temp = %u", temp);
    }

    struct node p1;
    p1.data = d;
    p1.next = NULL;
    *q=&p1;
    printf("\nEnd: Address at *q = %u\n", *q);
    printf("\n*q->data = %d next = %u", (*q)->data,(*q)->next );
} 
void display(struct node *q)
{
    printf("\n");
    while (q != NULL){
        printf(" -> %d",q->data);   
        q = q->next;        
    }
}

int main(int argc, char *argv[])
{
    struct node *p;
    p = NULL; /* empty linked list */

    printf("\nNo. of elements in the Linked List = %d", count(p));
    append(&p,1);
    display(p);
    append(&p,2);
    display(p);
    printf("\nNo. of elements in the Linked List = %d", count(p));
}
输出:

No. of elements in the Linked List = 0
Begin: Address at temp = 0
End: Address at *q = 6684096

*q->data = 1 next = 0
-> 1Segmentation fault
然而,当我替换

struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;

错误消失了。

有人能解释原因吗?

在这里,您可以使用局部变量的地址,使其在离开函数后可以访问:

*q=&p1;
然后您离开该功能。
当以后访问时,它将访问不再是局部变量的内存

您需要为变量分配内存。使用
malloc()
例如:


还有更多的问题,比如让列表以新节点开始,然后是NULL,这会丢失/泄漏以前的所有列表。但直接的问题是由于在一个过去的局部变量存在后引用了它的内存位置而引起的。

这里,您使用一个局部变量的地址,使它在您离开函数后可以访问:

*q=&p1;
然后您离开该功能。
当以后访问时,它将访问不再是局部变量的内存

您需要为变量分配内存。使用
malloc()
例如:

还有更多的问题,比如让列表以新节点开始,然后是NULL,这会丢失/泄漏以前的所有列表。但直接的问题是由于在一个过去的局部变量存在后引用它的内存位置造成的。

关于循环:

while (temp!= NULL){
这将导致
temp
包含
NULL
,因此这将一路跨过链表并离开链表的末尾

建议:

while (temp->next != NULL){
因为当链接列表指向链接列表中的最后一个“节点”时,它将停止单步遍历链接列表

然后需要使用
temp
作为指向链接列表中最后一个“节点”的指针(您要在其中附加新节点)

关于:

struct node p1;
p1.data = d;
p1.next = NULL;
*q=&p1;
temp = *q;
*q = malloc(sizeof(struct node))
temp->data = d;
temp->next = NULL;

the error is gone.
  • 这将在堆栈上创建新的“节点”。但是,当函数返回时,堆栈上的任何内容都会“消失”

  • q
    是指向链接列表中第一个“节点”的指针,而不是链接列表中最后一个“节点”。建议使用
    temp
    as(更正
    1后)
    指向链接列表中的最后一个“节点”

  • 每个“节点”都需要通过
    malloc()
    calloc()
    在“堆”内存中创建,因此它在函数退出后仍然存在

  • 关于:

    struct node p1;
    p1.data = d;
    p1.next = NULL;
    *q=&p1;
    
    temp = *q;
    *q = malloc(sizeof(struct node))
    temp->data = d;
    temp->next = NULL;
    
    the error is gone.
    
    不,错误没有消失。相反,这总是将新的“节点”作为链接列表中的第二个“节点”插入。(并断开链接列表中以下节点的链接。)

    发布的代码无法将所有分配的内存返回到堆中(通过调用
    free()
    ),结果是每次调用
    malloc()
    ,都会导致内存泄漏:

    while (temp!= NULL){
    
    这将导致
    temp
    包含
    NULL
    ,因此这将一路跨过链表并离开链表的末尾

    建议:

    while (temp->next != NULL){
    
    因为当链接列表指向链接列表中的最后一个“节点”时,它将停止单步遍历链接列表

    然后需要使用
    temp
    作为指向链接列表中最后一个“节点”的指针(您要在其中附加新节点)

    关于:

    struct node p1;
    p1.data = d;
    p1.next = NULL;
    *q=&p1;
    
    temp = *q;
    *q = malloc(sizeof(struct node))
    temp->data = d;
    temp->next = NULL;
    
    the error is gone.
    
  • 这将在堆栈上创建新的“节点”。但是,当函数返回时,堆栈上的任何内容都会“消失”

  • q
    是指向链接列表中第一个“节点”的指针,而不是链接列表中最后一个“节点”。建议使用
    temp
    as(更正
    1后)
    指向链接列表中的最后一个“节点”

  • 每个“节点”都需要通过
    malloc()
    calloc()
    在“堆”内存中创建,因此它在函数退出后仍然存在

  • 关于:

    struct node p1;
    p1.data = d;
    p1.next = NULL;
    *q=&p1;
    
    temp = *q;
    *q = malloc(sizeof(struct node))
    temp->data = d;
    temp->next = NULL;
    
    the error is gone.
    
    不,错误没有消失。相反,这总是将新的“节点”作为链接列表中的第二个“节点”插入。(并断开链接列表中以下节点的链接。)


    发布的代码无法将所有分配的内存返回到堆中(通过调用
    free()
    ),结果是每次调用
    malloc()

    都会导致内存泄漏。在得到答案后,您相应地更改了问题。这是一个不受重视的问题,被认为是一个“移动目标”问题。请避免这样。幸运的是,我认为我的帖子仍然回答了这个新问题。否则让我知道。不过,我可能会请你回到我回答的问题,然后指出我的答案中缺少什么。。。。(我看你现在接受了我的回答。我认为这是为了确认你仍然认为这是在回答……)玩得开心。@Yunnosch。很抱歉。我的编辑和你的回答是平行的。我尝试了不同的东西,找到了我可能出错的确切陈述,所以编辑了这篇文章,然后我看到了你的答案,这消除了我的困惑。所以我也接受了你的回答。如果这冒犯了你,那么我可以恢复我的编辑。“冒犯”太强了。在这种情况下,我认为一切都很顺利。不需要回复。另一方面,请理解不受欢迎的移动目标问题的概念,并尽可能避免。是的,我可以看到编辑和我的答案(特别是版本…)有一些似是而非的重叠。很好。别担心。(高兴地玩着我闪亮的新25代表…:-)在得到答案后,你相应地改变了你的问题。这是一个不受重视的问题,被认为是一个“移动目标”问题。请避免这样。幸运的是,我认为新的问题