如何在调用strcpy之前分配数组?

鉴于:

char test[] = "bla-bla-bla"; 

哪两个更正确?

 char *test1 = malloc(strlen(test)); strcpy(test1, test); 

要么

 char *test1 = malloc(sizeof(test)); strcpy(test1, test); 

这将适用于所有以null结尾的字符串,包括指向char数组的指针:

 char test[] = "bla-bla-bla"; char *test1 = malloc(strlen(test) + 1); strcpy(test1, test); 

您将无法获得char*指向的数组的正确大小或const char* 。 因此,该解决方案更通用。

无论是:

 #include  char *mine = strdup(test); 

您应该使用strlen ,因为如果将test更改为运行时定义的字符串, sizeof将无提示失败。 这意味着strlensizeof更安全,因为它会继续工作。

 char test[]="bla-bla-bla"; char *test1 = malloc(strlen(test) + 1); // +1 for the extra NULL character strcpy(test1, test); 

我认为sizeof是正确的。 其背后的原因是strlen(str)将给出字符串的长度(不包括终止null)。 如果你使用strcpy ,它实际上复制整个字符串,包括终止null,所以如果你在malloc使用strlen ,你将分配少一个字节。 但是sizeof给出了test指向的字符串的大小,包括终止null,因此你将得到正确大小的malloc chunk来复制字符串,包括终止null。

1)肯定会导致UB

2)可能导致UB(如果malloc失败)

我会选择2),因为这个结构有更好的机会按预期工作; 或者甚至更好我会在所有情况下编写一个按预期工作的版本(没有UB)。


编辑

  • 未定义的行为1)

    test1将为test的字符留出空间,但不会为终止'\0'留出空间。 对strcpy()的调用将尝试将'\0'写入不属于test1内存,因此写入UB。

  • 未定义的行为2)

    如果对malloc()的调用未能保留所请求的内存,则test1将被指定为NULL 。 将NULL传递给strcpy()调用UB。

应始终测试对malloc() (以及calloc()和朋友)的调用的返回值,以确保操作按预期工作。

(1)用strlen但不添加1肯定是不正确的。 如果你加1,它会有额外的好处,它也适用于指针,而不仅仅是数组。

另一方面,只要你的字符串实际上是一个数组,(2)是首选的,因为它导致编译时常量,而不是对strlen的调用(因此代码更快更小)。 实际上像gcc这样的现代编译器如果知道字符串是常量的话可能会优化strlen out,但是编译器可能很难确定它,所以我总是尽可能使用sizeof

如果它是一个关键路径, sizeof优于strlen因为它具有O(1)复杂性,可以节省CPU周期。