为何同一二叉树的不同指针删除结果存在差异?
重复释放内存导致程序崩溃的原因分析
先看你的代码片段:
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
相关产品推荐
相关产品推荐

