使用strcpy连接字符串

3

这是我的代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int main() {

 char f[] = "First";
 char s[] = "Second";
 char *tmp = malloc(strlen(f) + strlen(s) + 2);
 strcpy(tmp, f);
 strcpy(tmp, s);
 printf("%s", tmp);
 free(tmp);
 return 0;
}

我正在尝试连接f和s。问题是tmp只包含一个名为"Second"的数组。我在这里错过了什么?


将两个strcpy行交换一下,你会发现它只是说“first”,也可以说“firstd”。 - Joseph Le Brech
@Joseph Le Brech:我真的很想知道那会是怎样的? - sharptooth
不是strcpy,而是复制到字符串的开头而不是追加。你需要将strcpy复制到&(*tmp+sizeOf(tmp)),或者按照@dasblinkenlight所写的方式。 - Joseph Le Brech
7个回答

6

strcpy将字符串复制到目标的开头,你需要用strcat代替。


3
第二个strcpy覆盖了先前的内容。 它们都将其内容复制到tmp指针(在其开头)。 您应该使用tmp + strlen(f)
或者更好地使用strcat
甚至更好的是使用更安全的方法,如: strncpystrncat等。

4
在这种情况下,strncpy()strncat()都不能提供额外的安全性。 - sharptooth
1
@Throwback1986:n 版本在这里没有任何好处(确切地说是零)。 - sharptooth
@sharptooth:是的,我希望他没有在这里粘贴他的整个代码,在那种情况下使用n版本可能更有意义。 @sharptooth:是的,希望他没有在这里粘贴整段代码,否则使用n版本可能会更加合适。 - duedl0r
1
@sharptooth:同意,但让新程序员养成使用它们的习惯也无妨。 - Throwback1986
1
不建议使用“n”版本,因为它们并不会做你想要的事情。 - R.. GitHub STOP HELPING ICE

2
如果您坚持使用strcpy,您的代码应该稍作修改:
int main() {
    const char *f = "First";
    const char *s = "Second";
    char *tmp = malloc(strlen(f) + strlen(s) + 1);
    strcpy(tmp, f);
    strcpy(tmp+strlen(f), s);
    printf("%s", tmp);
    free(tmp);
    return 0;
}

出于安全原因,您应该考虑使用strncpy而不是strcpy。此外,strcat是用于连接C字符串的更常规的函数。

编辑这里是使用strncpy而不是strcpy的示例:

#define MAX 1024

int main() {
    const char *f = "First";
    const char *s = "Second";
    size_t len_f = min(strlen(f), MAX);
    size_t len_s = min(strlen(s), MAX);
    size_t len_total = len_f + len_s;
    char *tmp = malloc(len_total + 1);
    strncpy(tmp, f, len_f);
    strncpy(tmp+len_f, s, len_s);
    tmp[len_total] = '\0';
    printf("%s", tmp);
    free(tmp);
    return 0;
}

2
在这种情况下,使用strncpy()而不是strcpy()绝对没有任何好处。这就像微软强制在所有函数中使用带有_s后缀一样。 - sharptooth
3
除非您正在使用结构/二进制文件中的固定宽度、不一定以空字符结尾的字符串字段,否则绝不应该使用strncpy - R.. GitHub STOP HELPING ICE
1
你错了。strncpy 不是用于有界复制的。你把它和 BSD 函数 strlcpy 混淆了。在 C 中,唯一易于使用、安全、通用的字符串组装函数是 snprintf,除非你真的知道自己在做什么并且有充分的理由不这样做,否则你应该始终只使用 snprintf - R.. GitHub STOP HELPING ICE
1
@R.. 我真的觉得我在这里没有理解你的意思:你能否解释一下在我的示例中,memcpystrncpy更好(或者说有什么不同)?据我所知,如果在复制之前插入长度但在源字符串的'\0'之后读取,strncpy不会读取超过源字符串的'\0',并用'\0'填充输出缓冲区的其余部分,而memcpy会盲目地从一个位置复制len字节到另一个位置。 - Sergey Kalinichenko
1
@R.. 我理解你想要稍微扭曲定义以适应你的论点,但是 memcpy 复制了一个特定已知数量的 字节,而不是 字符。这从 memcpy 的签名中就可以明显看出,其中在相应位置上突出显示了一个 void*。另一方面,strncpy字符 - 再次非常显眼。但没关系,我理解你的观点。谢谢! - Sergey Kalinichenko
显示剩余6条评论

1
使用strcat()代替,它意味着根据MSDN文档附加一个字符串。strcpy()只是复制一个字符串。如果您不想使用strcat(),则应使用strncpy()或strcpy_s()指出位置。请参考文档。

1

您可能想使用strcat代替第二个strcpy调用,像这样:

strcpy(tmp, f);
strcat(tmp, s);

请注意,为tmp分配strlen(f) + strlen(s) + 1字节就足够了,无需分配strlen(f) + strlen(s) + 2字节。连接后,您将只得到一个字符串,因此只需要一个空字符。

1
问题在于你将第二个字符串复制到了第一个字符串的位置(strcpy()函数的第一个参数是要复制字符串的位置),这实际上覆盖了第一个字符串。以下是你需要的解决方案的示例:
size_t firstLen = strlen( f );
size_t secondLen = strlen( s );    
char *tmp = malloc(firstLen + secondLen + 1);
strcpy(tmp, f);
strcpy(tmp + firstLen, s);

这可以通过使用strcat()来实现,尽管这会导致在复制的字符串上多一次扫描。

1

这里是你想要的正确的习惯性安全方式:

size_t l = strlen(f);
char *tmp = malloc(l + strlen(s) + 1);
strcpy(tmp, f);
strcpy(tmp+l, s);

或者:

size_t l = strlen(f) + strlen(s) + 1;
char *tmp = malloc(l);
snprintf(tmp, l, "%s%s", f, s);

除非你编写想要避免引入 printf 依赖的嵌入式系统代码,否则我倾向于偏爱后者。

最后请注意,您应该测试 malloc 的失败,如果您只想打印字符串,则分配内存并复制字符串是无用且有害的 - 您可以使用以下方法:

printf("%s%s", f, s);

唉!如果你一定要使用单个字母的标识符,至少不要使用小写L(或大写I)。 - pmg
@pmg 这也是我注意到的第一件事 ;) - ouah

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