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

从文件读取结构体时出现Valgrind内存泄漏问题求助

内存泄漏问题分析与修复

Valgrind检测信息

==27091== HEAP SUMMARY:
==27091==     in use at exit: 96 bytes in 4 blocks
==27091==   total heap usage: 22 allocs, 18 frees, 11,347 bytes allocated
==27091==
==27091== 24 bytes in 1 blocks are definitely lost in loss record 1 of 2
==27091==    at 0x4847581: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==27091==    by 0x1092C6: detailNew (in /home/students/s/smelov.vp/test5/lab5)
==27091==    by 0x10944F: main (in /home/students/s/smelov.vp/test5/lab5)
==27091==
==27091== 72 bytes in 3 blocks are definitely lost in loss record 2 of 2
==27091==    at 0x4847581: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==27091==    by 0x1092C6: detailNew (in /home/students/s/smelov.vp/test5/lab5)
==27091==    by 0x109534: main (in /home/students/s/smelov.vp/test5/lab5)
==27091==
==27091== LEAK SUMMARY:
==27091==    definitely lost: 96 bytes in 4 blocks
==27091==    indirectly lost: 0 bytes in 0 blocks
==27091==      possibly lost: 0 bytes in 0 blocks
==27091==    still reachable: 0 bytes in 0 blocks
==27091==         suppressed: 0 bytes in 0 blocks

问题根源分析

1. detailNew函数的内存泄漏

在detailNew中,你通过calloc动态分配了detail *item,但返回item[0](结构体拷贝)后,没有释放item指向的内存,导致每次调用detailNew都会泄漏一块sizeof(detail)大小的内存。输入文件有4行数据,对应4次调用,正好匹配Valgrind提示的4块96字节泄漏(64位系统下detail结构体大小为24字节:2个8字节指针+4字节int,对齐后为24)。

2. detailNew的野指针问题

你在给item->id和item->name赋值后,立即调用free(id)和free(name),导致返回的结构体中id和name成员指向已释放的内存(野指针),后续访问这些指针会触发未定义行为。

修复方案

重构detailNew函数

不需要动态分配detail对象,直接在栈上创建结构体,为id和name分配内存后赋值给结构体成员,返回结构体拷贝即可:

detail detailNew(char* idBuf, char* nameBuf, int pcs){
    detail item;
    // 为id分配内存并拷贝内容
    item.id = calloc(strlen(idBuf) + 1, sizeof(char));
    strcpy(item.id, idBuf);
    // 为name分配内存并拷贝内容
    item.name = calloc(strlen(nameBuf) + 1, sizeof(char));
    strcpy(item.name, nameBuf);
    item.pcs = pcs;
    return item;
}

释放结构体成员的动态内存

在main函数中,释放list数组前,需要先遍历每个元素,释放其id和name指向的动态内存,否则会产生新的内存泄漏:

// ... 原代码中其他逻辑 ...
// 释放每个detail的id和name内存
for (size_t i = 0; i < amount; i++) {
    free(list[i].id);
    free(list[i].name);
}
free(list);
return 0;

额外优化(非泄漏问题,但建议修复)

main中使用!feof(details)作为循环条件是错误的,应该以fscanf的返回值判断是否读取成功,否则会导致最后一行重复处理。修改后的循环逻辑如下:

size_t amount = 0;
detail *list = NULL;
int inputCheck;
while ((inputCheck = fscanf(details, "%s %s %d", idBuf, nameBuf, &pcs)) == 3) {
    amount++;
    // 重新分配内存,用临时变量避免内存泄漏
    detail *temp = realloc(list, amount * sizeof(detail));
    if (temp == NULL) {
        // 内存分配失败时,先释放已分配的内存
        for (size_t i = 0; i < amount-1; i++) {
            free(list[i].id);
            free(list[i].name);
        }
        free(list);
        fclose(details);
        return 1;
    }
    list = temp;
    list[amount-1] = detailNew(idBuf, nameBuf, pcs);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:25:35