双向循环链表删除函数未达预期效果,求原因解析
双向循环链表删除函数异常原因解析
问题现象
我实现了双向循环链表的创建和删除函数,使用g++ 8.1.0编译执行后出现异常:
- 输入
5和1 2 3 4 5,删除函数执行前输出所有节点值和地址均正常 - 原始删除函数执行后,仅第二个节点值变为乱码,其余节点无变化,看起来只有循环外的
delete head;生效,循环内的delete temp;未起作用 - 将删除函数的参数改为指针的指针后,功能恢复正常
编译环境
g++ (x86_64-win32-sjlj-rev0, Built by MinGW-W64 project) 8.1.0 Copyright (C) 2018 Free Software Foundation, Inc.
原始代码
创建函数
struct Node { int val; Node* leftnode; Node* rightnode; }; void createlist(Node** head) { Node *p, *tail; int value, length = n; *head = new Node; (*head)->rightnode = NULL; (*head)->leftnode = NULL; tail = *head; while (length--) { scanf("%d", &value); p = new Node; p->val = value; p->leftnode = tail; tail->rightnode = p; tail = p; } Node* first = (*head)->rightnode; tail->rightnode = first; first->leftnode = tail; delete *head; *head = first; }
原始删除函数
void deletelist(Node* head, int n) { Node* first = head; head = head->rightnode; while (head != first) { Node* temp = head; head = head->rightnode; delete temp; } delete head; }
完整原始代码
#include<iostream> #include<cstdio> using namespace std; struct Node { int val; Node* leftnode; Node* rightnode; }; void createlist(Node** head); void showvalue2(Node* head, int n); void deletelist(Node* head, int n); int n; int main() { cin >> n; Node* head; createlist(&head); showvalue2(head, n); deletelist(head, n); showvalue2(head, n); } void createlist(Node** head) { Node *p, *tail; int value, length = n; *head = new Node; (*head)->rightnode = NULL; (*head)->leftnode = NULL; tail = *head; while (length--) { scanf("%d", &value); p = new Node; p->val = value; p->leftnode = tail; tail->rightnode = p; tail = p; } Node* first = (*head)->rightnode; tail->rightnode = first; first->leftnode = tail; delete *head; *head = first; } void showvalue2(Node* p, int n) { for (int i = 1; i <= n; i++) { cout << p->val << " " << p << endl; p = p->rightnode; } cout << endl; } void deletelist(Node* head, int n) { Node* first = head; head = head->rightnode; while (head != first) { Node* temp = head; head = head->rightnode; delete temp; } delete head; }
修改后正常的删除函数
void deletelist(Node** head, int n) { Node* first = *head; Node* current = (*head)->rightnode; while (current != first) { Node* temp = current; current = current->rightnode; delete temp; } delete current; *head = nullptr; // 可选:将头指针置空避免野指针 }
(注:你提供的修改后代码存在笔误,Node* first = head;应改为Node* first = *head;,此处已修正)
原因解释
参数传递方式问题
原始删除函数的参数是Node* head,属于值传递——函数内部的head只是主函数中head指针的副本。函数内修改head(如head = head->rightnode;)只会修改副本,不会影响主函数中的原指针。删除后的野指针访问
循环内删除第二个节点后,主函数中的head仍指向第一个节点,而第一个节点的rightnode还是指向已被删除的第二个节点地址(野指针)。执行showvalue2(head, n);时,第一个节点正常输出,第二个节点访问已释放内存导致值变乱码;由于原链表的指针链未更新,后续节点无法被正确遍历到,所以看起来其余节点无变化,但实际上它们的内存已被释放,属于非法访问。指针的指针的作用
修改为Node** head后,函数可以直接操作主函数中的head指针。遍历逻辑基于原链表的有效节点,逐个删除所有节点后,所有内存都被正确释放。最后将*head = nullptr;还能避免主函数中的指针变成野指针,提升安全性。原始删除函数的逻辑漏洞
原始删除函数删除节点时未修改链表的前驱/后继指针,虽然循环内实际删除了后续节点,但主函数中的原指针无法感知到链表结构的变化,导致输出时只能遍历到已失效的第二个节点,造成“仅第二个节点被删除”的假象。
内容的提问来源于stack exchange,提问作者WindnlesszzZ
相关产品推荐
相关产品推荐

