Valgrind检测到明确内存泄漏,跨函数释放失效问题求助
解决内存泄漏与Invalid Read问题的详细分析
咱们一步步拆解你遇到的问题,核心根源其实是指针传递方式错误加上内存大小计算失误,这两个问题叠加导致了Valgrind报的泄漏和非法访问错误。
问题1:值传递导致指针更新无法同步到主函数
你的read_file函数里,char **data是按值传递的——也就是说,函数内部的data只是主函数里data指针的一个拷贝。当你在函数里调用realloc(data, ++size)时,修改的只是这个局部拷贝的指针地址,主函数里的原始data指针完全没变化!
这就造成了两个致命问题:
- 主函数里的
data始终指向最初malloc(sizeof(*data))分配的小块内存,函数里realloc出来的新内存地址根本传不回去,最后彻底丢失,形成明确泄漏 - 当
realloc替换旧内存块时,主函数的data指针会指向已经被释放的内存,后续访问data[i]就触发了Valgrind的Invalid read错误
问题2:realloc内存大小计算错误
你写的realloc(data, ++size)是按字节分配内存,但data是char**类型(指针的指针),每个元素是一个char*指针(64位系统下占8字节)。正确的分配大小应该是size * sizeof(char*),否则会分配不足,导致越界访问。
修正后的完整代码
1. 修复read_file函数的指针传递与内存分配
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> int read_file(char *filename, char *search, char ***data) { int counter = 0; int size = 1; FILE *file = fopen(filename, "r"); // 必须检查文件是否成功打开 if (!file) { perror("Failed to open file"); return 0; } char c[100]; while (fgets(c, 100, file)) { if (strstr(c, search)) { while (fgets(c, 100, file)) { if (c[0] == '[') break; if (c[0] == '\n') continue; // 扩容逻辑:检查是否需要扩大指针数组 if (counter + 1 > size) { size++; // 用临时变量接收realloc结果,避免分配失败丢失原指针 char **temp = realloc(*data, size * sizeof(char*)); if (!temp) { perror("Realloc failed"); // 分配失败时要先释放已分配的内存,避免泄漏 for (int i = 0; i < counter; i++) { free((*data)[i]); } free(*data); fclose(file); return 0; } *data = temp; // 更新主函数里的指针 } // 分配单行内存,直接用strlen(c)+1更直观 (*data)[counter] = malloc(strlen(c) + 1); if (!(*data)[counter]) { perror("Malloc failed"); // 同样要清理已分配资源 for (int i = 0; i < counter; i++) { free((*data)[i]); } free(*data); fclose(file); return 0; } strcpy((*data)[counter], c); // 字符串复制用strcpy比memcpy更清晰 counter++; } } } fclose(file); return counter; // 返回实际存储的元素个数,而非容量size }
2. 主函数与free函数的适配修改
void free_pointer(char **data, int size) { for (int i = 0; i < size; ++i) { free(data[i]); } free(data); } int main() { char **data = malloc(sizeof(char*)); if (!data) { perror("Malloc failed"); return 1; } // 传入data的地址,让函数能修改主函数里的指针 int x = read_file("test.txt", "omg", &data); // 调试用打印 // for(int i = 0; i < x; ++i) { // printf("%s", data[i]); // } free_pointer(data, x); return 0; }
关键修正点总结
- 将
read_file的参数改为char ***data(指针的指针),这样函数内部能直接修改主函数里的data指针 realloc时计算正确的内存大小:size * sizeof(char*)- 用临时变量接收
realloc结果,避免分配失败导致原指针丢失 - 返回实际存储的元素个数
counter而非容量size,确保free时不会多循环或漏循环 - 增加所有内存分配、文件打开的错误检查,避免崩溃或隐性泄漏
这样修改后,Valgrind的泄漏和Invalid Read错误都会消失。
内容的提问来源于stack exchange,提问作者schauma
相关产品推荐
相关产品推荐

