为什么line2中的free使memcpy什么都不做?在malloc是o.k之前是免费的吗?

时间:2012-11-27 13:21:45

标签: c malloc free memcpy

void str_cpy(char **des,char* src){
   if(*des || *des==src)
     free(*des);
   *des = (char*)malloc(sizeof(char)*(strlen(src)+1));
   if(!*des)
     return ;
   memcpy ( *des, src, (strlen(src)+1)*sizeof(char) );
 }

为什么line2中的free会让memcpy什么都不做?在malloc之前免费是o.k ??

4 个答案:

答案 0 :(得分:4)

没有!!! :-)在尝试使用它之前你可以免费(src)! (在* dest == src的情况下,代码的第2行,即free(* dest)与free(src)基本相同,然后你使用src,从那一点开始就没有指向正确分配的内存块。)

尝试使用释放的内存会导致未定义的行为。什么东西未定义什么的!也许free已经将src中的第一个字节更改为0(在这种情况下strlen(src)== 0)或者memcpy可能检测到源内存未正确分配或者可能正在进行其他操作。不值得追究为什么你会得到这个行为的问题。如果您更改构建设置(调试/优化等)或在不同的系统上构建程序(实际上它是库,而不是您使用的编译器在这里有所不同),您可能会得到不同的结果。

无论如何,当* dest == src时,你不需要free,strlen,malloc和copy;你可以回来。

void str_cpy(char **des,char* src){
   if(*des==src) return;
   ...
 }

一般来说,使用你的函数的人会期望你不会对第二个参数src做任何有趣的事情,例如改变它的内容,或者确实释放它的内存。我还将参数类型更改为const char * src。虽然这并不能阻止你释放src内存块,但它会使函数的预期用法更加清晰。

实际上,功能签名存在另一个更大的问题。 * dest可能指向堆中先前分配的内存(唯一的情况是free(* dest)正常,假设* dest!= src,当然)或先前分配的堆栈内存(在这种情况下是free(* dest) )是不正常的),但也可能指向静态分配的内存(字符串文字)或不指向分配的内存周期。

标准库函数通过不使用此类签名(即使用char **类型的参数)来避免此问题。

与您正在做的事情最相关的功能的签名是:

 char * strcpy(char *restrict s1, const char *restrict s2);

 char * strncpy(char *restrict s1, const char *restrict s2, size_t n);

 char * strdup(const char *s1);

更多信息位于:http://www.manpagez.com/man/3/strncpy/http://www.manpagez.com/man/3/strncpy/

这些功能都不必担心内存的分配位置。这三个都要求它们的参数是有效的指针(静态或动态分配(堆/堆栈)内存。我怀疑strdup实际上是最适合你正在做的事情(你似乎想为重复的字符串分配新的内存) .sccpy和strncpy不分配新内存。(有关详细信息,请参阅上面的文档链接。)

你看到那里的模式吗? strdup返回一个指向新分配的内存的指针(与malloc完全一样),strcpy和strcpy采用char *参数,不分配内存。这些函数都不必处理你的函数所具有的问题,也就是确定(不可能在C中执行)什么样的内存* dest指向的函数。 Kernighan和Ritchie之所以选择这样做是有原因的:-)

您可以提供一些文档,使其明确指出* dest必须指向堆中先前分配的内存块或者等于NULL。但是,优秀的图书馆设计师不会这样做,因为它将责任传递给用户(因为用户犯错误)。

依靠文档(即让图书馆设计师将责任交给其用户)是一条危险的道路。最好完全避免这个问题。好的C代码从函数签名开始: - )

最后一点:您在代码中使用了两次strlen()。出于性能原因,最好只使用一次并将其返回值存储在局部变量中,并使用当前调用strlen()的变量。

答案 1 :(得分:3)

在C中,您只能释放由malloccallocrealloc分配的内存。 因此释放除此之外的内存是Undefined behaviour

我的情况不清楚是什么*des。以及它是由malloccalloc还是realloc分配的。

或者你在调用环境中这样做了

char des[20]= "hello , world \n";

或可能是

char * des= "hello . world \n";

答案 2 :(得分:1)

正如评论中指出的那样,您的功能需要文档。如果输入正确,它可以完全按照您的意愿工作:

这有效:

char * str1 = "hello";
char * str2 = malloc(6);   // Of course this is pointless since you'll free it anyway
str_cpy(&str2, str1);

这样做:

char * str1 = "hello";
char * str2 = NULL;
str_cpy(&str2, str1);

但是这个:

char * str1 = "hello";
char * str2;
str_cpy(&str2, str1);

或者这个:

char * str1 = "hello";
char str2[6];
str_cpy(&str2, str1);

或者这个:

char * str1 = "hello";
char * str2 = str1;
str_cpy(&str2, str1);

会崩溃并燃烧。您需要在评论中记下函数的所有前/后条件。

答案 3 :(得分:0)

void str_cpy(char **des,char* src){
   if(*des || *des==src)
     free(*des);
   *des = (char*)malloc(sizeof(char)*(strlen(src)+1));
   if(!*des)
     return ;
   memcpy ( *des, src, (strlen(src)+1)*sizeof(char) );
 }
  • 在malloc之前没有必要释放,它可能包含一些垃圾值,并且你释放了导致的垃圾(Core Dumped)。
  • 如果(* des == src)你释放了des,这意味着'src'也被释放了,下面你在memcpy中使用了src。

正确的方法:

void str_cpy(char **des,char* src){
   *des = (char*)malloc(sizeof(char)*(strlen(src)+1));
   if(!*des)
     return ;
   memcpy ( *des, src, (strlen(src)+1)*sizeof(char) );
 }