正确的方式来为字符串分配空间,然后向该空间插入字符是什么?

7

我有两个字符串,str1和str2。我想在堆上将它们以空格为连接符进行拼接。我使用以下方法为它们分配空间:

char *concat = (char*) malloc(strlen(str1) + strlen(str2) + 1);

我能只做这个吗:

strcat(concat, str1);
strcat(concat, str2);

那么concat会给我一个将两个字符串连接在一起的堆上位置吗?我问这个问题是因为似乎strcat实际上会将str1添加到使用malloc分配的空间的末尾。这是正确的吗?因此,str1将出现在位置strlen(str1)+ strlen(str2)+1。

我问这个问题的原因是我正在使用上述方法,但在valgrind中遇到错误: 条件跳转或移动取决于未初始化的值

3个回答

16

strcat(dest, src)的实际作用是在从dest开始往后查找null字节,并在那里写入src字符串。

在使用malloc之后,内存的内容是未定义的,因此您当前的代码可能会执行许多操作,其中大部分都不正确。如果在strcat之前执行concat[0] = 0,则您的代码可以正常工作,但需要三次搜索str1的长度--一次为strlen,再一次为第一个strcat,最后一次为第二个strcat

然而,我建议使用memcpy代替:

size_t len1 = strlen(str1), len2 = strlen(str2);
char *concat = (char*) malloc(len1 + len2 + 1);

memcpy(concat, str1, len1);
memcpy(concat+len1, str2, len2+1);

这是因为您从一开始就知道想要将两个字符串的字节放在哪里以及有多少字节。


+1 绝对是一个非常好的方法。我可能会使用 memmove() 而不是 memcpy(),因为虽然在这种情况下 memcpy() 是安全的,但它并不总是安全的,而 memmove() 总是安全的。 - Jonathan Leffler
4
不要在这里使用 memmove,会让人感到困惑。任何使用 memmove 应该用于说明你正在做一些非常不同和不寻常的事情。如果我看到在这里使用 memmove,我会花一两分钟试图弄清楚为什么有人使用它,并且是否有什么可疑的东西正在发生... - R.. GitHub STOP HELPING ICE

6
你想要执行strcpy和strcat操作:
strcpy(concat, str1);
strcat(concat, str2);

strcat依赖于存在空终止符('\0')来确定开始位置。如果你只是使用malloc和strcat,那么会发生一些不好的事情。

而且,strcpy和strcat都不会进行任何隐式分配或重新分配。


5
我个人会这样做:
size_t length = strlen(str1) + strlen(str2) + 1;
char *concat = malloc(sizeof(char) * length);

if(concat == NULL)
{
    // error
}

snprintf(concat, length, "%s%s", str1, str2);

“snprintf()”通常是一个不错的解决方案,尽管在这里它有点过度设计。提到错误检查+1。 - Jonathan Leffler
2
不要使用strlen来计算长度。使用length=snprintf(0,0,"%s%s",str1,str2);或者直接使用asprintf(并确保包含自己的版本 - 它是对snprintf的一个简单包装器 - 用于不包含这个GNU扩展的系统)。 - R.. GitHub STOP HELPING ICE
2
R在此自己解释他上面的评论(必读以理解建议):https://dev59.com/X1bTa4cB1Zd3GeqP7RXk#5615561 - San

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