【问题标题】:Memory Leak: Reading and returning line from file内存泄漏:从文件中读取和返回行
【发布时间】:2017-09-02 11:48:40
【问题描述】:

我正在尝试从文件中读取一行并返回该行。但是,我不断收到内存泄漏,丢失了 4000 个字节,并且比 allocs 少了一个。我不知道为什么会这样。下面是函数。

char *readLine(FILE *input, int lineNum) {

    char *string = calloc(MAX_LEN, sizeof(char));
    rewind(input);
    char *check = fgets(string, MAX_LEN, input);

    int stringLength = strlen(string);

    if (stringLength > MAX_LEN) {
        printf("Line too long to stdout.");
        free(string);
        return EXIT_SUCCESS;
    } else
    if (check == NULL) {
        free(string);
        return NULL;
    }
    return string;
}

我这样称呼它:

char *line = readLine(input, 0);

注意:忽略lineNum的东西,解决内存泄漏后我会添加。

那么,内存泄漏的原因和位置是什么?彻底的解释将非常有帮助。谢谢大家!

编辑:这是调用readLine()的函数:

char *makeSummary(FILE *input, int summaryNum) {
   char *line = readLine(input, 0); //Get first line
   int lineLength = strlen(line);

    if (summaryNum == 1) {
        //Get the last line of file by looping till NULL
        lineNum = 10; 

        line = readLine(input, lineNum);
        //Do more stuff with line
   }
   free(line);
}

【问题讨论】:

  • 使用后必须 free() `line'。但总的来说,在 C 中必须为此功能“设计”约定并严格使用。 C++ 有更多的可能性
  • 返回EXIT_SUCCESS;打破了你自己的约定
  • 1) if(stringLength > MAX_LEN) { 永远不会是真的 2) if(check < 0) { 你在这里比较一个指向 -1 的指针。
  • 1) 好的,这给了我另一个需要解决的问题 2) 哎呀,这意味着 if(check == NULL)。谢谢。
  • 你的泄漏是显而易见的。你读了一行,如果summaryNum == 1 为真,你改变行号并读另一行,盲目地覆盖刚刚读的前一行,因此泄漏它。在伤口上加盐,你永远不会检查初始 readLine 调用的结果,因此随后的 strlen 可以通过在 null 上执行轻松调用未定义的行为指针。

标签: c file memory-leaks fgets


【解决方案1】:

您的代码存在一些问题:

  • 在函数readLine 中,在测试check == NULL 之前计算string 的长度。这可能是不正确的。

  • 此外,string 的长度根据定义小于MAX_LEN,您的测试总是错误的。您可能需要检查该行是否以换行符结尾以检测截断。

  • 您返回EXIT_SUCCESS,但函数返回char *。编译器没有检测到这种差异,因为EXIT_SUCCESS 被定义为0,所以return EXIT_SUCCESS;return NULL; 相同。

  • 在函数makeSummary 中,您似乎用下一次调用readLine() 返回的指针覆盖了line。您必须line = readLine(input, 0)之前调用free(line);

  • 您在readLine() 中调用rewind(),因此您会继续从输入文件中读取同一行,除非无法找到该文件(例如终端),如果您正在从常规文件中读取,你永远不会到达终点。

这是一个分配更少字节的修改版本:

char *readLine(FILE *input, int lineNum) {
    char buf[MAX_LEN];
    size_t len;

    if (!fgets(buf, sizeof(buf), input)) {
        return NULL;
    }
    if ((len = strlen(buf)) == MAX_LEN - 1 && buf[len - 1] != '\n') {
        printf("Line too long from file.");
        return NULL;
    }
    return strdup(buf);
}

char *makeSummary(FILE *input, int summaryNum) {
   char *line = readLine(input, 0); //Get first line
   if (line == NULL)
       return NULL;

   int lineLength = strlen(line);

    if (summaryNum == 1) {
        //Get the last line of file by looping till NULL
        lineNum = 10; 

        free(line);
        line = readLine(input, lineNum);
        //Do more stuff with line
   }
   free(line);
   return NULL;
}

请注意,strdup() 不是标准的,可能在非 Posix 系统上不可用,但很容易实现:

#include <string.h>

char *strdup(const char *s) {
    size_t size = strlen(s) + 1;
    char *p = malloc(size);
    if (p != NULL) {
        memcpy(p, s, size);
    }
    return p;
}

【讨论】:

  • 谢谢,这真的很有帮助,而且很彻底。标记为答案:)。
【解决方案2】:

您的函数在需要返回它时不会free(string)(这是有道理的),所以除非您未发布的代码的某些部分是free-ing 它(而且这里的任何人都无法告诉,出于明显的原因),有你的泄漏。

【讨论】:

  • 行稍后在不再需要时调用它的函数中被释放。所以如果这是唯一的泄漏问题,我能做些什么来阻止泄漏?抱歉,我对 C 很陌生。谢谢
  • @littleCoder - 使用另一个free 位置编辑您的问题,因为泄漏可能发生在那个阶段。当您测试泄漏时,您会获得有关分配函数的信息,而不是发生泄漏的位置。
【解决方案3】:

谢谢大家,特别是@WhozCraig。问题在于使用 readLine 的函数在实际读取所需的行号之前没有释放 Line。现在已修复此问题,一切正常。

【讨论】:

    猜你喜欢
    • 2012-11-19
    • 1970-01-01
    • 2023-01-23
    • 2021-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    相关资源
    最近更新 更多