在没有内存泄漏的情况下替换char *

时间:2014-03-22 20:35:45

标签: c memory memory-leaks

我正在尝试创建一个find-and-replace函数,但它可以工作,但valgrind报告了大量的内存泄漏。

看看:

void repl(char** str) {

    // build a new string (simulating find&replace)

    char* replacement = (char*)malloc(7);
    strcpy(replacement, "my ass");

    // this causes "free(): invalid pointer" crash
    //free(*str);

    *str = replacement; // return to caller
}

/* main function */
int main (int argc, char **argv) {

    // out original string
    char* str = "memory leak here";
    repl(&str); // replace something 1st time
    repl(&str); // 2nd time
    repl(&str); // 3rd time

    printf("%s\n",str); // look at output

    exit(0);
}

当“免费”到位时,您将获得:

*** glibc detected *** ./test: free(): invalid pointer: 0x0000000000401013 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f264e7ecb96]
....  

但是,如果free不存在,则会出现内存泄漏(valgrind输出):

==26236== LEAK SUMMARY:
==26236==    definitely lost: 14 bytes in 2 blocks
==26236==    indirectly lost: 0 bytes in 0 blocks
==26236==      possibly lost: 0 bytes in 0 blocks
==26236==    still reachable: 7 bytes in 1 blocks
==26236==         suppressed: 0 bytes in 0 blocks

我还没有完全熟悉指针,所以请耐心等待。 也许这不是最好的方法,所以请提出更好的查找和替换方法,没有内存泄漏。

我试着返回结果,但之后我也有泄漏。

5 个答案:

答案 0 :(得分:4)

glibc建立什么?

glibc诊断与str并不始终指向malloc分配的内存段的事实有关,这是{{1}的要求之一}}。换一种说法;您第一次调用free时,repl的值指向非malloced内存段会导致str行为异常。


free建立什么?

valgrind诊断是存在的,因为没有valgrind的使用(当前出现故障),freemalloc分配的内存永远不会被释放,因此;你正在泄露记忆。


建议的解决方案

我觉得用文字解释它而不是给你一个有效的实现更好,因为你似乎渴望通过实践来学习。

  1. 不接受指向指针的指针,而是接受repl并返回指向由以下内容组成的新内存段的指针传入的字符串的修改版本。此新内存段已通过pointer-to-char分配,

  2. 重命名您的函数,以明确它正在分配需要释放的内存,

  3. 记录您的函数,以便调用者知道它负责malloc内存,而不是 replace-function

答案 1 :(得分:3)

你不能删除/释放“这里的内存泄漏”字符串导致它实际上没有你释放,它是程序代码中的一个常量字符序列,这就是为什么你得到无效指针的运行时错误。删除空闲时,丢失的14个字节会导致您分配7个字节三次,但只能分配最后一个字节。

答案 2 :(得分:2)

freemalloc,这就是全部。在freemalloc未分配的内存上调用realloc会调用未定义的行为。这就是您第一次拨打free会导致错误的原因; str指向的内容未动态分配。

这似乎也是一个糟糕的设计。该函数将缓冲区作为输入。它不应该对这个缓冲区做出假设,除了它有效写入。它不应该在其输入上调用free;确保记忆清理是调用者的工作。

同样,你甚至不需要malloc。您可以直接写入缓冲区并强制用户分配它(这更规范。)在您需要返回动态分配的内存的情况下,您应该记录返回的内存必须由调用者释放。您的模型必须与所有权保持一致。

答案 3 :(得分:2)

这是您传递给repl函数的字符串所有权问题:一旦执行此操作

*str = replacement;

*str指向的内存永远消失,成为内存泄漏。这就是为什么你需要在重新分配之前释放它。

但这不是结束!这意味着您无法将字符串常量或在静态或自动存储中分配的char数组传递给repl,因为无法释放它。因此,您需要先复制原始文件,然后再将其传递给repl

void repl(char** str) {
    char* replacement = malloc(7);
    strcpy(replacement, "my ass");
    // This will no longer be a problem - see the change in main()
    free(*str);
    *str = replacement; // return to caller
}

/* main function */
int main (int argc, char **argv) {
    // Now that the original string is malloced,
    // free() inside repl() is no longer a problem:
    char* str = malloc(17);
    strcpy(str, "memory leak here");
    repl(&str); // replace something 1st time
    repl(&str); // 2nd time
    repl(&str); // 3rd time
    printf("%s\n",str); // look at output
    exit(0);
}

请注意,在实际的repl中,使用realloc可能会更好 - 它有可能加速小型替换。

答案 4 :(得分:0)

在呼叫者中添加免费

/* main function */

int main (int argc, char **argv) {

    // out original string
    char* str = "memory leak here";
    repl(&str); // replace something 1st time
    free(str);
    repl(&str); // 2nd time
    free(str);
    repl(&str); // 3rd time

    printf("%s\n",str); // look at output
    free(str);
    exit(0);
}