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

为何同一二叉树的不同指针删除结果存在差异?

重复释放内存导致程序崩溃的原因分析

先看你的代码片段:

typedef struct TreeNode
{
    int data;
    TreeNode *lchild, *rchild;
} TreeNode;
TreeNode *CreateBTNode(TreeNode *bt) // pre-build
{
    char ch;
    cin >> ch;
    if (ch == '#')
        bt = nullptr;
    else
    {
        bt = (TreeNode *)malloc(sizeof(TreeNode));
        bt->data = ch;
        bt->lchild = CreateBTNode(bt->lchild);
        bt->rchild = CreateBTNode(bt->rchild);
    }
    return bt;
}
void DeleteBiTree(TreeNode *&bt) 
{
    if (!bt)
        return;
    DeleteBiTree(bt->lchild);
    DeleteBiTree(bt->rchild);
    free(bt);
    bt = nullptr;
}
void PreOrder(TreeNode *bt)
{
    if (bt)
    {
        cout << bt->data << " ";
        PreOrder(bt->lchild);
        PreOrder(bt->rchild);
    }
}
int main()
{
    TreeNode *tree = CreateBTNode();
    TreeNode *tmp = tree;

    DeleteBiTree(tree);       // line 1

    DeleteBiTree(tmp);        // line 2

    PreOrder(tree);           // line 3
    
    return 0;
}

问题核心原因

程序崩溃是因为重复释放同一块内存空间,这属于C/C++中的未定义行为,会直接触发内存访问异常。

详细拆解过程

  • 初始状态:tree和tmp指向同一块二叉树根节点的内存地址。
  • 执行第1行DeleteBiTree(tree)时:
    • 函数参数是指针引用TreeNode *&bt,递归释放完所有子节点后,最后会把传入的tree指针本身置为nullptr。
    • 但tmp指针没有被任何操作修改,它仍然指向已经被free的那块内存,此时tmp成为野指针。
  • 执行第2行DeleteBiTree(tmp)时:
    • 函数首先检查if (!bt),但此时bt(即tmp)不是nullptr,会继续递归访问它的左、右子节点。
    • 这些子节点的内存已经被第一次DeleteBiTree调用释放,此时访问已释放的内存(解引用野指针),或者再次尝试free已释放的内存,都会触发程序崩溃(比如段错误)。
  • 第3行PreOrder(tree)正常无输出:因为tree已经被置为nullptr,函数中的if (bt)条件不成立,直接返回,不会访问任何无效内存。

修复建议

要避免这种问题,要么在第一次释放后手动把tmp置为nullptr,要么确保同一块内存只被释放一次。比如在第1行之后加上tmp = nullptr;,这样第二次调用DeleteBiTree(tmp)时会直接返回,不会触发异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:05:10