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

Realloc()引发无法定位的内存泄漏问题求助

问题描述

测试add_filename()和init_filename()两个函数时发现内存泄漏。这两个函数负责将文件行读取到动态分配的字符串数组中,init_filename()初始化数组,add_filename()添加新元素,两者均返回数组起始指针。已确保realloc()不会丢失指针,设置了内存分配错误标识,也释放了能想到的内存,但仍存在泄漏。

代码

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

char **add_filename(char **filenames, char *new_file, int *file_num, int *flag);
char **init_filename(char *new_file, int *flag);

int main() {
    FILE *file;
    file = fopen("file.txt", "r");
    char *buffer = 0;
    size_t buf_size = 0;
    size_t chars = 0;
    int file_num = 0, check = 1;
    // char ch;
    if (file != NULL) {
        char **files;
        while ((int)(chars = getline(&buffer, &buf_size, file)) > 0) {
            if (!file_num) {
                files = init_filename(buffer, &check);
                file_num++;
            }
            files = add_filename(files, buffer, &file_num, &check);
            printf("files = %s", files[file_num - 1]);
            free(buffer);
            buffer = NULL;
            if (check == 0) {
                printf("we have problems\n");
                break;
            }
        }
        free(buffer);
        buffer = NULL;
        fclose(file);
        if (files) {
            for (int i = 0; i < file_num; i++) {
                free(files[i]);
            }
        } 
    }
    return 0;
}

char **init_filename(char *new_file, int *flag) {
    char **init = malloc((1) * sizeof(char*)); //
    if (init) {
        init[0] = malloc((strlen(new_file) + 1) * sizeof(char));
        if (!init[0])
            *flag = 0;
    } else {
        *flag = 0;
    }
    return init;
}

char **add_filename(char **filenames, char *new_file, int *file_num, int *flag) {
    char **temp = realloc(filenames, (*file_num + 1) * sizeof(char *));
    if (temp) {
        filenames = temp;
        filenames[*file_num] = malloc((strlen(new_file) + 1) * sizeof(char));
        if (filenames[*file_num] != NULL) {
            strcpy(filenames[*file_num], new_file);
            *file_num = *file_num + 1;
        } else {
            *flag = 0;
        }
    } else {
        *flag = 0;
    }
    return filenames;
}

Valgrind输出结果

==5881== HEAP SUMMARY:
==5881==     in use at exit: 32 bytes in 1 blocks
==5881==   total heap usage: 15 allocs, 14 frees, 6,285 bytes allocated
==5881== 
==5881== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5881==    at 0x484DCD3: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==5881==    by 0x1094E2: add_filename (test.c:72)
==5881==    by 0x109335: main (test.c:23)
==5881== 
==5881== LEAK SUMMARY:
==5881==    definitely lost: 32 bytes in 1 blocks
==5881==    indirectly lost: 0 bytes in 0 blocks
==5881==      possibly lost: 0 bytes in 0 blocks
==5881==    still reachable: 0 bytes in 0 blocks
==5881==         suppressed: 0 bytes in 0 blocks
==5881== 
==5881== For lists of detected and suppressed errors, rerun with: -s
==5881== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

ASan输出结果

Direct leak of 32 byte(s) in 1 object(s) allocated from:
    #0 0x7f200c4b4c18 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:164
    #1 0x5591559a2a8a in add_filename /home/licht/Documents/Knowledge/school21/inProgress/C3_SimpleBashUtils-0/src/test.c:72
    #2 0x5591559a2631 in main /home/licht/Documents/Knowledge/school21/inProgress/C3_SimpleBashUtils-0/src/test.c:23
    #3 0x7f200c029d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: 32 byte(s) leaked in 1 allocation(s).

问题原因与修复方案

核心泄漏原因

泄漏的32字节是add_filename()中realloc分配的数组本身的内存——主函数只释放了数组内的每个字符串元素files[i],但未释放数组顶层指针files。

修复步骤

  1. 释放数组顶层指针
    在主函数中,释放完所有files[i]后,添加free(files):
if (files) {
    for (int i = 0; i < file_num; i++) {
        free(files[i]);
    }
    free(files); // 释放数组本身
}
  1. 修复重复添加的逻辑
    第一次初始化数组后,立刻调用add_filename会导致重复存储同一行内容,调整循环逻辑:
while ((int)(chars = getline(&buffer, &buf_size, file)) > 0) {
    if (!file_num) {
        files = init_filename(buffer, &check);
        file_num++;
    } else {
        files = add_filename(files, buffer, &file_num, &check);
    }
    // 后续代码保持不变
}
  1. 完善错误处理
    当内存分配失败时,需要释放已分配的所有资源再退出:
if (check == 0) {
    printf("we have problems\n");
    if (files) {
        for (int i = 0; i < file_num; i++) {
            free(files[i]);
        }
        free(files);
    }
    free(buffer);
    fclose(file);
    return 1;
}

内容的提问来源于Stack Exchange,提问作者plush guardian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:45:36