strdup()的用法

4
假设我们有一个结构体:
struct Person {
    char *name;
};

struct Person *Person_create(char *name){
  struct Person *who = malloc(sizeof(struct Person));
  assert(who != NULL);
  who->name = strdup(name);
  return who;
}

void Person_destroy(struct Person *who){
  assert(who != NULL);
  free(who->name);
  free(who);
}

而主要功能是:
  int main(int argc,char *argv[]){

  struct Person *mike = Person_create("mike");
  Person_print(mike);
  Person_destroy(mike);

  return 0;
}

如果没有strdup()函数,上述代码将无法正常工作。Valgrind会提示你尝试使用free(who->name)释放的地址不是malloc'd。这背后的故事是什么?当我malloc结构体时,我难道没有malloc那块内存吗?而strdup()有什么区别?


你确定这符合你的测试用例吗? - ouah
是的,原始代码更复杂,但当我运行这个程序时,它会显示“***错误:在'./ex1'中free():无效指针:0x00000000004006fd ***”。 - baris_ercan
1
这段代码看起来没问题。有两种可能性。要么 Person_print 做了一些不好的写入操作,但我不太相信这个可能性;要么你的程序与这个测试用例不同。 - ouah
1
另一个选项是我没有完全阅读问题。当然,如果您不使用strdup并保留free,则会遇到一些麻烦。 free仅存在是因为strdup调用malloc来复制字符串。 - ouah
3个回答

5
在您的代码中,每个Person对象都涉及两个独立的内存块:struct Person对象本身和名称的单独内存块。该单独的内存块由结构体内的name指针指向。当您使用malloc分配struct Person时,您没有为名称分配任何内存。它是另一个独立的内存块,应该单独分配内存。
如何为名称分配内存完全取决于您。如果您像上面的代码一样使用strdup(它实质上是malloc的包装器),则最终必须通过free释放它。
您没有解释“不使用strdup()函数”是什么意思。如果您只是这样做
who->name = name;

然后你使得who->name指针直接指向字符串文字内存,该内存被占用的字符串为"mike"。字符串字面量驻留在静态内存中。您不允许free它们。这就是valgrind告诉您的内容。


是的,实际上就是这样,删除free(who->name)这一行解决了所有错误,谢谢。 - baris_ercan

0

使用malloc分配结构体会为指针名称分配内存,但它不会为名称指向的内存分配任何内存。此时who->name将是一些随机垃圾值,因此释放它没有任何意义。

strdup在内部使用malloc为其复制的字符串分配内存。一旦从strdup获得了指针,您应该在完成后释放它。


-3

strdup不调用malloc,它只是字符串操作。你只需要为结构体指针分配内存,而不是内部成员。


2
文档有所不同:“新字符串的内存是使用malloc(3)获得的,并且可以使用free(3)释放。” - Šimon Tóth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接