【问题标题】:C Memory leak, concating in a while loopC内存泄漏,在while循环中连接
【发布时间】:2015-09-04 13:08:35
【问题描述】:

我的程序有内存泄漏,但我想我已经找到了它的原因。我正在做的是使用 concat 函数将标准输入中的所有单词添加到一个字符串中。

这是一个函数:

Word* readWords(FILE *file) {
    char buffer[201]; 
    char* all_words_string = "";   
    Word* word_node_list = NULL;   

    char* cp = fgets(buffer, 201, file);
    while (cp != NULL) {   
        all_words_string = concat(all_words_string, cp); 
        cp = fgets(buffer, 201, file);
    } 
    char** word_list = wordList(all_words_string); //You can probably ignore this
    free(all_words_string);
    word_node_list = count_words(word_list); //Ignore this
    freeWordList(word_list); //Ignore this
    free(word_list); //Ignore this

   return word_node_list;
}

调用concat函数:

char* concat(char *s1, char *s2){
    char *result = malloc(strlen(s1)+strlen(s2)+1);
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

我认为是 while 循环

    while (cp != NULL) {   
        all_words_string = concat(all_words_string, cp); 
        cp = fgets(buffer, 201, file);
    } 

对我的内存泄漏负责。因为我在 concat 中分配了所有这些空间,然后删除指向它的指针,然后我只释放 this 的最后一个实例。

这是我的内存泄漏的原因吗?如果是这样,我该如何解决?

【问题讨论】:

    标签: c memory-leaks


    【解决方案1】:

    您已正确分析问题。每个malloc()calloc() 都应该与相应的free() 配对,而您没有这样做。您的代码还存在一些其他不妥之处,例如未能检查函数结果中的错误情况。

    我建议您查看realloc(),这将大大缓解您的问题。根据上述规定,它允许您避免在free() 之前插入额外的malloc() 调用。此外,它的行为将允许您在初始化 all_words_string 时避免一些轻微的怪异。例如:

    Word *readWords(FILE *file) {
        char *all_words_string = NULL;  /* NULL, not "" */
        char *cp;
        /* ... */
    
        cp = fgets(buffer, 201, file);
        while (cp != NULL) {   
            all_words_string = concat(all_words_string, cp); 
            cp = fgets(buffer, 201, file);
        } 
    
        /* ... */
    
        free(all_words_string);
    
        /* ... */
    }
    
    char* concat(char *base, const char *to_add){
        /* when its first argument is NULL, realloc() works like malloc(): */
        char *result = realloc(base, strlen(base) + strlen(to_add) + 1);
    
        if (result != NULL) { /* realloc() (and malloc()) returns NULL on failure */
            /* no need to copy the original string */
            /* no need to free it, either */
            strcat(result, to_add);
        }
        return result;
    }
    

    【讨论】:

    • 我喜欢realloc,但它需要注意的是不能使用字符串常量(会崩溃)。所以你不能做concat("foo", "bar")
    • @DarkDust,你说对了一半——当 first 参数是字符串常量时,带有realloc() 的这个版本不起作用,甚至不能容纳@987654332 @第一个参数不违反const-正确性。我刚刚更新了它以容纳 const 第二个参数,但是,第二个参数的字符串常量应该没问题。当然,这对于 OP 的情况来说都不是问题。
    【解决方案2】:

    您需要将结果存储在一个新变量中,以便在分配新值之前释放旧变量。例如:

    // Need to allocate an empty string dynamically so we can free it
    // later on.
    char* all_words_string = malloc(1);
    all_word_string[0] = 0; 
    
    ...
    
    char* tmp = concat(all_words_string, cp);
    if (tmp != NULL && tmp != all_words_string) {
        free(all_words_string);
        all_words_string = tmp;
    }
    

    【讨论】:

    • 太好了,我之前尝试过,但是在分配之前内存被破坏了,但是我将 all_words_string 的初始化更改为 char* all_words_string = malloc(10);它有效,谢谢!问题已回答
    【解决方案3】:

    当您查找内存泄漏时,您需要计算mallocs 和frees 的数量并确保它们匹配。

    您可能会说在这段代码中有一个malloc 和一个free,这是真的。但是 - 你从循环内部调用malloc

    所以每次你循环这个循环:

    while (cp != NULL) {   
        all_words_string = concat(all_words_string, cp); 
        cp = fgets(buffer, 201, file);
    } 
    

    你调用 malloc 一次。当你跳出循环时,你已经完成了未指定数量的 malloc(可能为零)并且没有释放。

    然后你这样做:

    免费(所有字串);

    所以你现在已经完成了 1 个free 和 0、1 或两个或更多 mallocs。

    第一个会导致崩溃(因为您要释放一个不是malloced 的字符串),第二个会很好,第三个会导致内存泄漏。

    你需要编写类似这样的代码:

    char *all_words_string = strdup("");
    ...
    while (cp != NULL) {   
        char *tmp = concat(all_words_string, cp); 
        free(all_words_string);
        all_words_string = tmp;
        cp = fgets(buffer, 201, file);
    } 
    ...
    free(all_words_string)
    

    【讨论】:

      【解决方案4】:

      似乎你每次进入时都会造成泄漏:

      char* concat(char *s1, char *s2){
          char *result = malloc(strlen(s1)+strlen(s2)+1);
          strcpy(result, s1);
          strcat(result, s2);
          return result;
      }
      

      这里不调用 malloc,而是考虑调用 realloc。 替换下一行

      char *result = malloc(strlen(s1)+strlen(s2)+1);

      s1 = realloc(s1, (strlen(s1)+strlen(s2)+1));

      这应该负责动态释放先前分配的内存。

      【讨论】:

        猜你喜欢
        • 2011-03-13
        • 1970-01-01
        • 2012-04-08
        • 1970-01-01
        • 2022-01-21
        • 2021-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多