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。
修复步骤
- 释放数组顶层指针
在主函数中,释放完所有files[i]后,添加free(files):
if (files) { for (int i = 0; i < file_num; i++) { free(files[i]); } free(files); // 释放数组本身 }
- 修复重复添加的逻辑
第一次初始化数组后,立刻调用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); } // 后续代码保持不变 }
- 完善错误处理
当内存分配失败时,需要释放已分配的所有资源再退出:
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
相关产品推荐
相关产品推荐

