C语言递归收集树叶子节点指针时出现段错误问题求助
问题排查:递归遍历树形结构收集叶子节点时的段错误
调用init_model()函数时,尝试递归遍历树形结构,将最底层TreeNode(叶子节点)的指针添加到TreeNode指针类型的动态数组中,但遍历数组打印时出现段错误。相关代码如下:
void rec_find_inputs(TreeNode* root, TreeNode** arr, int* len_arr) { if (!(root->num_children)) { arr = realloc(*arr, *len_arr * sizeof(TreeNode*)); arr[*len_arr] = root; (*len_arr)++; } else { for (int i = 0; i < root->num_children; i++) { rec_find_inputs(root->children[i], arr, len_arr); } } } void init_model(TreeNode* neuron_config) { int rec_params_len = 0; TreeNode** rec_params_arr = (TreeNode**) malloc(sizeof(TreeNode*) * 1); rec_find_inputs(neuron_config, rec_params_arr, &rec_params_len); printf("--------------\n"); printf("%d\n", rec_params_len); for (int i = 0; i < rec_params_len; i++) { printf("%f\n", rec_params_arr[i]->data); } }
问题原因分析
- 指针传递错误:
rec_find_inputs函数中的arr是按值传递的二级指针,realloc修改的是函数内部的局部指针变量,并不会影响外部的rec_params_arr。当realloc重新分配内存后,局部的arr指向新地址,但外部的rec_params_arr仍然指向旧的内存块,后续操作会导致野指针访问或内存越界,最终触发段错误。 - 内存分配大小错误:代码中
realloc(*arr, *len_arr * sizeof(TreeNode*))的计算逻辑错误。当*len_arr为0时,会分配0字节的内存,此时执行arr[*len_arr] = root会直接越界访问非法内存;即使*len_arr不为0,当前分配的空间也只能容纳现有数量的元素,无法新增一个叶子节点的指针。
修正后的代码
修正递归收集函数
void rec_find_inputs(TreeNode* root, TreeNode*** arr, int* len_arr) { // 先判断root是否为空,避免空指针访问 if (!root) { return; } if (!(root->num_children)) { // 重新分配内存,容量为当前长度+1,确保能容纳新元素 *arr = realloc(*arr, (*len_arr + 1) * sizeof(TreeNode*)); // 使用*arr访问外部传入的数组指针,赋值新的叶子节点 (*arr)[*len_arr] = root; (*len_arr)++; } else { for (int i = 0; i < root->num_children; i++) { // 传递数组指针的地址,确保递归中能修改外部数组的地址 rec_find_inputs(root->children[i], arr, len_arr); } } }
修正初始化函数
void init_model(TreeNode* neuron_config) { int rec_params_len = 0; // 初始可以分配1个元素空间,也可以直接设为NULL(realloc会自动处理) TreeNode** rec_params_arr = malloc(sizeof(TreeNode*) * 1); // 传入数组指针的地址,让递归函数能修改它 rec_find_inputs(neuron_config, &rec_params_arr, &rec_params_len); printf("--------------\n"); printf("%d\n", rec_params_len); for (int i = 0; i < rec_params_len; i++) { printf("%f\n", rec_params_arr[i]->data); } // 释放动态分配的内存,避免内存泄漏 free(rec_params_arr); }
额外注意事项
- 新增了
if (!root)的判断,防止树形结构中存在空节点时触发空指针访问错误。 - 使用完动态数组后必须调用
free(rec_params_arr),避免内存泄漏。 - 初始的
malloc可以替换为TreeNode** rec_params_arr = NULL;,因为realloc(NULL, size)的效果等同于malloc(size),这样代码更简洁。
内容的提问来源于stack exchange,提问作者Tomas Whiteley
相关产品推荐
相关产品推荐

