分段错误错误单向链表 C++ [已关闭]

Segmentation fault error singly linked lists C++ [closed]

提问人:M1001 提问时间:11/11/2023 最后编辑:M1001 更新时间:11/11/2023 访问量:85

问:


编辑问题以包括所需的行为、特定问题或错误以及重现问题所需的最短代码。这将帮助其他人回答这个问题。

12天前关闭。

为什么会出现错误:

int main(){
    lista *head, *x;
    head = nullptr;
    const int len = 3;
    int y[len] = {13, 4, 32};
    for(int i = len - 1; i >= 0; i--){
        x = new lista;
        x -> val = y[i];
        x -> next = head;
        head = x;
    }
    lista *p = head;
    // Changing lines are the next ones
    while(p->next != nullptr){
        p = p->next;
    }
    delete p;
    p = nullptr;

    print_lista(head);
    return 0;
}

但事实并非如此:

int main(){
    lista *head, *x;
    head = nullptr;
    const int len = 3;
    int y[len] = {13, 4, 32};
    for(int i = len - 1; i >= 0; i--){
        x = new lista;
        x -> val = y[i];
        x -> next = head;
        head = x;
    }
    lista *p = head;
    // Changing lines are the next ones
    while(p->next->next != nullptr){
        p = p->next;
    }
    delete p->next ;
    p->next = nullptr;

    print_lista(head);
    return 0;
}

它也不能以这种方式工作

while(p->next != nullptr){
    p = p->next;
}
p = p->next;
delete p;
p = nullptr;

这是给定的错误:

受监控的命令转储核心

分段故障

这不是一回事吗?在第一种情况下,p 是倒数第二个元素的下一个值,在第二种情况下,p 是倒数第三个元素的下一个值,因此 p->next 应该是倒数第二个元素的下一个值。 结构如下:

struct lista{
    int val;
    lista *next;
};

错误发生在“delete...;”行中

本·沃伊特(Ben Voigt)的编辑

为什么?如果我运行这样的测试:

lista *p = head;
while (p->next->next != nullptr){
    p = p->next;
}
cout << p->next;
lista *z = head;
while (z->next != nullptr){
    z = z->next;
}
cout << endl << z;

p 和 z 都是0x5575909e3eb0的,它们不是一样吗?

C++ 列表 指针 singly-linked-list

评论

1赞 tadman 11/11/2023
删除指针后,无需将指针分配给 null,除非需要向代码的其他部分发出信号,表明某些内容已被删除。此外,在 C++ 中使用优先于 C 的无类型。nullptrNULL
5赞 tadman 11/11/2023
“良好做法”在这里是非常有争议的。您是否在调试器中运行过它?当你的价值是什么?这个指针是你所期望的吗?pdelete p
1赞 Ben Voigt 11/11/2023
@tadman:因为为了能够找到并修改指向要删除的项的指针,这是必要的......
2赞 Pepijn Kramer 11/11/2023
你仍然错过了很多C++,这种编程风格更有可能有错误(只是说)。你是否仅限于老师的这种编码?
1赞 Jesper Juhl 11/11/2023
如果你想要一个单向链表,就在标准库中。std::forward_list

答:

4赞 Ben Voigt 11/11/2023 #1

问题在于,在失败的代码中,您正在解除分配列表中的最后一项,而不会将其从列表中删除。结果是一个包含悬空指针的列表,因此遍历该列表的后续操作具有未定义的行为。

工作代码确实将其从列表中分离出来。


为了回答你的思想实验,让我们让它变得更简单。

std::cout << head << '\n';
lista* z = head;
std::cout << z << '\n';

z = nullptr;
// now how many items are in the list?
std::cout << head << '\n';
std::cout << z << '\n';

// are `head` and `z` really equivalent?
z = head;
head = nullptr;
// now how many items are in the list?
std::cout << head << '\n';
std::cout << z << '\n';

评论

0赞 M1001 11/11/2023
为什么?如果我运行这样的测试:lista *p = head;while (p->next->next != NULL){ p = p->next ;} cout << p->next;lista *z = 头部;while (z->next != NULL){ z = z->next ;} cout << endl << z;p 和 z 都是0x5575909e3eb0的,它们不是一样吗?
0赞 M1001 11/11/2023
这在评论中是不可缩进的,我编辑了问题
1赞 Ben Voigt 11/11/2023
和 都是指向列表中项的指针的副本。 实际上是列表的一部分。 将该对象从列表中分离。 在不更改列表的情况下擦除副本。pzp->nextp->next = nullptr;z = nullptr;
0赞 M1001 11/11/2023
非常感谢,我现在明白了,我表现得好像 p 和 head 是一样的,而不仅仅是指向同一件事,但现在另一个问题出现在我面前,如果它只是删除一个副本,为什么它会抛出致命错误?它应该不起作用
1赞 Ben Voigt 11/11/2023
p是指向列表中的真实节点,所以 ,解除分配事物指向的(即 ),解除分配的是真实项目而不是副本。 不作用于指针变量。delete p;p*pdeletep