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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:35:50