strdup和内存泄漏

时间:2013-12-20 21:07:57

标签: c memory-leaks strdup

strdup是否每次都分配另一个内存区域并创建另一个指针?

例如:以下代码会导致内存泄漏吗?

void x(char** d, char* s){
    *d = strdup(s);
}

int main(){
    char* test = NULL;
    x(&test, "abcd");
    x(&test, "etc");
    return 0;
}

3 个答案:

答案 0 :(得分:6)

是的,程序会泄漏内存,因为它会分配对象然后丢失对它们的引用。

第一次发生这种情况的行:

 x(&test, "etc");

变量test包含在前一次调用x时分配的指针的唯一副本。对x的新调用将覆盖该指针。此时,指针泄漏。

这就是泄漏内存的意思:丢失对现有动态分配存储的所有引用

main函数返回时发生第二次泄漏。此时,test变量被销毁,该变量保存指向"etc"字符串副本的指针的唯一副本。

有时在C程序中,我们有时不关心第二种类型的泄漏:程序终止时未释放的内存,但是在循环中不会一次又一次地分配(因此它不会导致失控记忆增长问题)。

如果程序被集成到另一个程序(例如作为共享库)中,原始main函数成为可以在同一程序环境中重复调用的启动函数,则两个泄漏都将变为问题。

POSIX strdup函数的行为类似于:

char *strdup(const char *orig)
{
   size_t bytes = strlen(orig) + 1;
   char *copy = malloc(bytes);
   if (copy != 0)
     memcpy(copy, orig, bytes);
   return copy;
}

是;它每次都分配新的存储空间。

如果C映像中有垃圾收集器(如Boehm),那么泄漏的存储可能会被回收,因此strdup能够为第二次分配重用相同的内存。 (但是,只有一次分配后,垃圾收集器才会启动,除非它在压力测试模式下运行以清除错误。)

现在,如果您想使用realloc实际重用内存,那么您可以按以下方式更改x函数:

#include <stdlib.h>
#include <string.h>

void *strealloc(char *origptr, char *strdata)
{
    size_t nbytes = strlen(strdata) + 1;
    char *newptr = (char *) realloc(origptr, nbytes); /* cast needed for C++ */
    if (newptr)
      memcpy(newptr, strdata, nbytes);
    return newptr;
}

(顺便说一句,以str开头的外部名称位于ISO C保留的命名空间中,但strealloc是一个名字太好的拒绝。)

请注意,界面不同。我们不传入指向指针的指针,而是提供类似realloc的接口。调用者可以检查null的返回值以检测分配错误,而不会在这种情况下不方便地用null覆盖指针。

main功能现在看起来像是:

int main(void)
{
    char *test = strealloc(NULL, "abcd");
    test = strealloc(test, "etc");
    free(test);
    return 0;
}

和以前一样,没有错误检查。如果第一个strealloc失败,则test为空。这不会因为它被覆盖了,strealloc的第一个参数可能为空。

只需要一个free来堵塞内存泄漏。

答案 1 :(得分:1)

是的,如果您不释放它,它会分配内存和泄漏。来自man page

  

strdup()函数返回一个指向新字符串的指针,该字符串是字符串s的副本。使用malloc(3)获取新字符串的内存,可以使用free(3)释放。

new_s = strdup(s)基本上等同于:

new_s = malloc(strlen(s)+1);
strcpy(new_s, s);

答案 2 :(得分:1)

考虑strdup的以下定义:

#include <string.h>
char *strdup(const char *string);
  

strdup通过调用stringmalloc的副本预留存储空间。此函数的字符串参数应包含标记字符串结尾的null字符(\0)。请务必释放通过调用strdup保留的存储空间。

你必须自己free字符串。