strcpy和strdup的区别

90

我了解到strcpy函数用于复制字符串,而strdup函数返回指向新字符串的指针以复制该字符串。

您能否解释一下在哪些情况下您更喜欢使用strcpy和在哪些情况下您更喜欢使用strdup

6个回答

126

strcpy(ptr2, ptr1) 相当于 while(*ptr2++ = *ptr1++)

strdup 则相当于

ptr2 = malloc(strlen(ptr1)+1);
strcpy(ptr2,ptr1);

(memcpy版本可能更有效率)

所以如果你想要将复制的字符串在另一个函数中使用(因为它是在堆区域创建的), 你可以使用strdup, 否则strcpy就足够了。


7
除了最后一句话有点令人困惑外,你的答案很好。我猜你的意思是strdup()函数创建的字符串的生命周期可以超出当前函数的末尾,但这种情况本来就可能存在(如果strcpy()的目标是调用者提供的缓冲区、全局变量或手动使用malloc()new分配的内存)。 - j_random_hacker
1
是的,如果调用者提供的缓冲区是全局变量或动态指针本身,则无需使用strdup。我刚刚指出了其中一个用例场景,感谢您完成它。 - Abdul Muheedh
12
真的很喜欢 while(*ptr2++ = *ptr1++)! :) - Aloys
1
在 while 循环中,退出条件是如何工作的? - sbhatla
5
在C语言中,字符串以空字节结尾,该字节的值为false,而赋值表达式则会计算出被赋的值。 - user1115652
@Aloys 如果你在程序中使用了明确的 while(*ptr2++ = *ptr1++),不要忘记将指针恢复到它们的原始值。在 while 结束后,它们将位于空终止符位置。 - Paulo Carvalho

68

strcpystrncpy 函数是 C 标准库中的函数,用于操作已有的内存。也就是说, 必须提供内存让这些函数将字符串数据复制进去,而且作为一个必然的结果, 必须自己找出需要多少内存。

相比之下,strdup 是一个 Posix 函数,它会为你执行动态内存分配。它返回指向新分配内存的指针,并且已经将字符串复制到了这块内存中。但是, 现在负责这块内存并最终必须使用 free 释放掉它。

这使得 strdup 成为“隐藏的 malloc”便利函数之一,这也可能是它不是标准库的一部分的原因。只要你使用标准库,就知道调用每个 malloc/calloc 后必须调用一个 free。但是像 strdup 这样的函数引入了一个隐藏的 malloc,你必须像管理内存时处理 malloc 一样来处理它。(另一个类似的隐藏分配函数是 GCC 的 abi::__cxa_demangle()。)请注意!


2
啊,我一直想知道为什么这不在stdlib中,现在我知道了。 - Maury Markowitz

18

strdup 会在堆上分配内存用于新字符串,而使用 strcpy (或更安全的 strncpy 变体),我可以将一个字符串复制到已经在堆或栈上预先分配好的内存中。


1
为什么要强调“either”?难道不能使用strcpy将内容复制到静态缓冲区中吗? - Kerrek SB
我试图强调这两个函数的使用差异,而不会在回答中混杂太多内存管理问题。但是,关于静态缓冲区,你说得对。 - Oren
如果您不想混淆,可以在“预分配内存”后结束答案 :-) - Kerrek SB
小细节:strncpy并不比strcpy更安全,因为它不能保证dest以空字符结尾。更糟糕的是,目标缓冲区中任何未使用的空间都将填充空字符。该函数从未旨在用于一般用途。如果您必须使用其中之一,请最好使用strcpy并手动终止dest。 - JohnF

15
被接受的回答中,strdup 的实现如下所示:
ptr2 = malloc(strlen(ptr1)+1);
strcpy(ptr2,ptr1);

然而,那有点次优,因为strlenstrcpy都需要通过检查每个字符是否为\0来找到字符串的长度。

使用memcpy应该更有效率:

char *strdup(const char *src) {
    size_t len = strlen(src) + 1;
    char *s = malloc(len);
    if (s == NULL)
        return NULL;
    return (char *)memcpy(s, src, len);
}

1
很好的答案,将strcpy的概念用于实现strdup与以高效的方式实现它的实际可行性分开。 - Michael Gaskill
鉴于memcpy依赖于知道字符串的长度,在任何情况下都会调用strlen。memcpy本身相当于while (len--) { *ptr2++ = *ptr1++ },每次进行减法、赋值和零测试,然后仍然必须运行一个赋值,然后是两个后增量及其赋值。因此,这种memcpy技术似乎不太高效。这些似乎是相当琐碎的区别和想象中的优化。 - user2895783

0

char *strdup(char *pszSrch);

strdup函数将分配与原始字符串相同大小的存储空间。如果存储分配成功,则将原始字符串复制到副本字符串中。

strdup在失败时返回NULL。如果未分配内存,复制失败,则strdup返回NULL


0

对于*memcpy,可以使用另一种实现方式,而不需要增加dest和src的增量:

while ( n-- ) { dest[n] = src[n] }


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