7

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

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

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

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

3 回答 3

9

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

第一次发生这种情况是:

 x(&test, "etc");

该变量test保存在上一次调用中分配的指针的唯一副本xx对覆盖该指针的新调用。此时,指针泄漏。

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

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

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

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

POSIXstrdup函数的行为与此类似:

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需要一个来堵塞内存泄漏。

于 2013-12-20T21:16:53.963 回答
5

是的,如果您不释放它,它会分配内存并泄漏。从手册页

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

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

new_s = malloc(strlen(s)+1);
strcpy(new_s, s);
于 2013-12-20T21:12:26.847 回答
2

考虑以下定义strdup

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

strdupstring通过调用为副本保留存储空间malloc。此函数的字符串参数应包含一个null字符 ( \0) 标记字符串的结尾。请记住释放调用strdup.

你必须free自己串。

于 2013-12-20T21:59:40.450 回答