You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

双向循环链表删除函数未达预期效果,求原因解析

双向循环链表删除函数异常原因解析

问题现象

我实现了双向循环链表的创建和删除函数,使用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;,此处已修正)

原因解释

  1. 参数传递方式问题
    原始删除函数的参数是Node* head,属于值传递——函数内部的head只是主函数中head指针的副本。函数内修改head(如head = head->rightnode;)只会修改副本,不会影响主函数中的原指针。

  2. 删除后的野指针访问
    循环内删除第二个节点后,主函数中的head仍指向第一个节点,而第一个节点的rightnode还是指向已被删除的第二个节点地址(野指针)。执行showvalue2(head, n);时,第一个节点正常输出,第二个节点访问已释放内存导致值变乱码;由于原链表的指针链未更新,后续节点无法被正确遍历到,所以看起来其余节点无变化,但实际上它们的内存已被释放,属于非法访问。

  3. 指针的指针的作用
    修改为Node** head后,函数可以直接操作主函数中的head指针。遍历逻辑基于原链表的有效节点,逐个删除所有节点后,所有内存都被正确释放。最后将*head = nullptr;还能避免主函数中的指针变成野指针,提升安全性。

  4. 原始删除函数的逻辑漏洞
    原始删除函数删除节点时未修改链表的前驱/后继指针,虽然循环内实际删除了后续节点,但主函数中的原指针无法感知到链表结构的变化,导致输出时只能遍历到已失效的第二个节点,造成“仅第二个节点被删除”的假象。

内容的提问来源于stack exchange,提问作者WindnlesszzZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 13:30:40