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

C语言递归构建二叉树动态数组触发double free错误求助

问题分析与修复方案

核心错误:realloc的新地址无法同步回主函数

你的Sczytaj函数里,Drzewiec是按值传递的指针——函数内部的Drzewiec只是原指针的副本。当你调用realloc重新分配内存后,函数内的指针会指向新的内存块,但main里的原始Drzewiec指针还停留在旧地址上。而realloc在分配新内存时,通常会释放旧内存块,这就导致main里的指针变成了野指针。最后main调用free(Drzewiec)时,实际上是在释放一块已经被realloc回收的内存,自然触发了double free detected错误。

其他待修正的问题

  1. 内存扩容逻辑顺序颠倒:你先把*c(数组容量)加2再调用realloc,但没有考虑当前索引是否真的需要扩容,逻辑不够严谨。
  2. 输出循环边界错误:用wielkość(容量)作为循环上限,会输出数组中未初始化的内存区域,应该用实际存储元素的indeks作为边界。
  3. 冗余的指针写法:&*a完全等价于a,没必要多此一举,直接传a即可。
  4. 缺少错误检查:没有检查malloc和realloc的返回值,也没处理scanf的输入错误,容易导致程序崩溃。

修复后的完整代码

#include <stdio.h>
#include <stdlib.h>

void Sczytaj(int** Drzewiec, int* a, int* b, int* c) {
    int Obecny, oindeks;
    // 检查输入是否有效
    if (scanf("%d", &Obecny) != 1) {
        fprintf(stderr, "输入无效,请输入整数\n");
        return;
    }
    
    oindeks = *a;
    // 先判断是否需要扩容:当前索引已达到或超过数组容量时扩容
    if (oindeks >= *c) {
        *c += 2; // 按你的逻辑每次扩容2个元素,也可以改成翻倍更高效
        int* new_ptr = realloc(*Drzewiec, sizeof(int) * (size_t)*c);
        if (!new_ptr) {
            fprintf(stderr, "内存分配失败\n");
            exit(EXIT_FAILURE);
        }
        *Drzewiec = new_ptr; // 更新主函数中的原始指针
    }
    
    (*Drzewiec)[oindeks] = Obecny;
    
    if (Obecny == 0) {
        *a += 1;
        return;
    }
    
    // 处理非空节点,递归读取左右子树
    *a += 1;
    *b += 1;
    Sczytaj(Drzewiec, a, b, c);
    Sczytaj(Drzewiec, a, b, c);
}

int main(void) {
    printf("请输入数据(每行一个整数,0代表空节点):\n");
    int wielkość = 1, indeks = 0, indeks_bez_zera = 0;
    int* Drzewiec = malloc(sizeof(int) * (size_t)wielkość);
    
    if (!Drzewiec) {
        fprintf(stderr, "初始内存分配失败\n");
        return EXIT_FAILURE;
    }
    
    Sczytaj(&Drzewiec, &indeks, &indeks_bez_zera, &wielkość);
    
    printf("\n存储的二叉树数据:\n");
    for (int i = 0; i < indeks; i++) {
        printf("%d\n", Drzewiec[i]);
    }
    
    printf("\n最后使用的索引:%d\n非空节点数量:%d\n数组当前容量:%d\n", indeks, indeks_bez_zera, wielkość);
    
    free(Drzewiec);
    return EXIT_SUCCESS;
}

关键修复点说明

  1. 传递指针的指针:把函数参数改成int** Drzewiec,调用时传&Drzewiec,这样函数内部可以直接修改主函数里的指针变量,确保所有递归调用和主函数都使用最新的内存地址。
  2. 修正扩容逻辑:先检查当前索引是否超出数组容量,再进行扩容,避免不必要的内存操作。
  3. 错误处理增强:添加了malloc、realloc和scanf的错误检查,让程序更健壮。
  4. 输出逻辑修正:用indeks(实际存储的元素个数)作为循环上限,避免输出未初始化的垃圾值。

测试示例

输入:

1
0
0

输出:

请输入数据(每行一个整数,0代表空节点):
1
0
0

存储的二叉树数据:
1
0
0

最后使用的索引:3
非空节点数量:1
数组当前容量:3

此时程序不会触发double free错误,运行完全正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 09:45:28