C语言二叉树程序输出正常后触发Segmentation fault段错误求助
问题相关代码
#include <stdio.h> #include <stdlib.h> typedef struct node { int number; struct node *left; struct node *right; } node; void print_tree(node *root); void free_tree(node *root); int main(void) { node *tree = NULL; node *n = malloc(sizeof(node)); if (n == NULL) { return 1; } // root n->number = 2; n->left = NULL; n->right = NULL; tree = n; n = malloc(sizeof(node)); if (n == NULL) { free_tree(tree); return 1; } n->number = 1; n->left = NULL; n->right = NULL; tree->left = n; n = malloc(sizeof(node)); if (n == NULL) { free_tree(tree); return 1; } n->number = 3; n->left = NULL; n->right = NULL; tree->right = n; print_tree(tree); free_tree(tree); return 0; } void print_tree(node* root) { if (root == NULL) { return; } print_tree(root->left); printf("%i\n", root->number); print_tree(root->right); } void free_tree(node* root) { if (root == NULL) { return; } free_tree(root->left); free_tree(root->right); free(root); }
问题现象
- 代码可正常完成二叉树中序遍历,按换行顺序输出1、2、3,符合预期
- 程序运行结束前触发Segmentation fault段错误
- 调试定位到错误触发位置为
free_tree函数中的free_tree(root->left);语句
问题根源
你贴出的代码逻辑本身没有问题,正常编译运行不会触发段错误。出现该问题基本是以下三类原因导致,其中第一种概率最高:
- 本地实际运行的代码中,
free_tree的释放顺序错误
如果本地代码把free(root);写在了两个递归调用之前,就会触发你遇到的问题:
这种错误下,// 错误实现示例 void free_tree(node* root) { if (root == NULL) { return; } free(root); // 提前释放当前节点内存,root成为野指针 free_tree(root->left); // 访问已释放内存的left成员,直接触发段错误 free_tree(root->right); }print_tree没有内存释放操作,遍历逻辑完全正常,可以正确输出1、2、3;但到内存释放阶段,先释放节点再访问节点的指针成员,属于典型的野指针访问,崩溃位置和你调试定位的位置完全吻合。 - 堆内存被意外破坏
常见触发场景:- malloc分配内存时大小写错,比如写成
malloc(sizeof(node*)),只分配了指针长度的内存,远小于node结构体的实际大小。后续给节点的number、left、right成员赋值时会越界写入,破坏堆块的管理元数据。这类问题不会立刻崩溃,print阶段内存还未被回收,可能侥幸正常输出,但free阶段堆管理器校验元数据失败就会触发段错误。 - 新malloc的节点漏写
n->left = NULL; n->right = NULL;初始化,指针值为堆上的随机垃圾地址,递归遍历时访问到非法地址就会崩溃。这类问题大多在print阶段就会触发,概率相对较低。
- malloc分配内存时大小写错,比如写成
- 代码修改后未保存或未重新编译,运行的是旧版本的错误二进制文件,属于新手高频踩坑场景。
修复方案
- 严格按照后序遍历顺序实现
free_tree:先递归释放左子树、再递归释放右子树、最后释放当前节点,也就是你贴出的写法,free(root);必须放在两个递归调用的最后。 - 检查所有malloc调用的内存大小,确保是
sizeof(node)而非sizeof(node*);所有新创建的节点必须手动将left、right指针初始化为NULL,不要依赖malloc返回内存的默认值。 - 删除旧的编译产物,重新保存所有代码文件后完整编译再运行。
内容的提问来源于stack exchange,提问作者omelias
相关产品推荐
相关产品推荐

