strcpy与memcpy

97
memcpy()strcpy()之间有什么区别?我尝试用程序找到答案,但两者都给出了相同的输出。
int main()
{
    char s[5] = { 's', 'a', '\0', 'c', 'h' };
    char p[5];
    char t[5];
    strcpy(p, s);
    memcpy(t, s, 5);
    printf("sachin p is [%s], t is [%s]", p, t);
    return 0;
}

输出

sachin p is [sa], t is [sa]

1
请参见 https://dev59.com/qHE85IYBdhLWcg3wNwx3 - Doug Currie
9个回答

141

如何看到这种效果

编译并运行此代码:

void dump5(char *str);

int main()
{
    char s[5]={'s','a','\0','c','h'};

    char membuff[5]; 
    char strbuff[5];
    memset(membuff, 0, 5); // init both buffers to nulls
    memset(strbuff, 0, 5);

    strcpy(strbuff,s);
    memcpy(membuff,s,5);

    dump5(membuff); // show what happened
    dump5(strbuff);

    return 0;
}

void dump5(char *str)
{
    char *p = str;
    for (int n = 0; n < 5; ++n)
    {
        printf("%2.2x ", *p);
        ++p;
    }

    printf("\t");

    p = str;
    for (int n = 0; n < 5; ++n)
    {
        printf("%c", *p ? *p : ' ');
        ++p;
    }

    printf("\n", str);
}

它将生成以下输出:
73 61 00 63 68  sa ch
73 61 00 00 00  sa

您可以看到,“ch”被memcpy()复制,但不被strcpy()复制。

3
你好,我知道这篇帖子有点旧了,但是我有两个问题想要请教。第一个问题是关于 printf("%2.2x ", *p); - 为什么您将 printf 的格式限制为 2.2?另外,我根本看不到任何小数点... 第二个问题是关于 printf("%c", *p ? *p : ' '); - 这个测试到底检查了什么?如果 *p 是什么?感谢您的回答! - Peter Cerba
16
在printf语句中,"x"表示"十六进制"。"2.2"的意思是:只有两个数字,且必须为两个数字。*p测试的意思是:"如果你遇到了空字符,则打印一个空格。" - egrunin

113

strcpy在遇到NUL('\0')字符时停止,而memcpy不会。您在此处看不到影响,因为printf中的%s也会在NUL处停止。


2
@Sachin:将pt初始化为某些值(例如全部为空格),然后在复制后,比较p[3]t[3]strcpy没有超过p[2],因为它找到了空字符,但是按照指示进行的memcpy复制了五个字符。 - Cascabel
11
小小的注记:strcpy在遇到NUL字符(一个“L”)时停止。NULL(两个“L”)是一个编译时的常量,用于指向不指向任何有效对象的指针。 - Daniel Stutzbach
1
如果目标字符串和源字符串重叠,strcpy会导致段错误吗? - Alcott

13

strcpy函数在找到源字符串的空字符终止符时结束。而memcpy函数需要传递一个大小参数。在您提供的案例中,对于两个字符数组,printf语句都会在找到空字符终止符后停止,但是您会发现t[3]t[4]也有复制的数据。


10

strcpy会将源字符串中的字符逐一复制到目标字符串,直到找到源字符串中的NULL或'\0'字符为止。

while((*dst++) = (*src++));

memcpy会将给定尺寸为n的源数据不考虑其内容复制到目标位置,而不是像strcpy只能复制字符。

如果你确定源数据包含加密数据或二进制数据,应使用memcpy

strcpy已过时,请使用strncpy


我不知道你在哪里看到strcpy()被弃用了。 - Rohan Bari
2
@RohanBari 如果这是一个只有 MSVC 经验的人再次谈论“_deprecated functions_”,那么这真是一件令人愤怒的事情。 - An Ant
strcpy()并不是被废弃的,只是不鼓励使用(因为strncpy()对缓冲区溢出的容忍度较低)。这两者完全不同。 - egrunin

4

主要区别在于memcpy()总是复制您指定的确切字节数; 另一方面,strcpy()会复制直到读取NUL(又称0)字节,然后在此之后停止。


3

由于您的字符串 s 中有空字符,printf 不会显示该字符后面的任何内容。 pt 之间的区别将在第4和第5个字符中体现。p 没有任何内容(它们将是垃圾),而 t 将具有 'c''h'


3
  • 行为差异:strcpy在遇到NULL'\0'时停止复制。
  • 性能差异:memcpy通常比strcpy更高效,因为strcpy总是扫描它复制的数据。

就性能而言,它确实取决于编译器和平台。我在两个不同的环境下进行了测试,并得到了以下结果:在Linux ARMv7L上,memcpystrcpy快1.5倍。然而,在Linux x86_64上,使用GCC 13.1.1和Clang 16.0.5,strncpystrcpy都比memcpy快10%(可能是因为现代编译器的实现?)。你的情况可能会有所不同,所以你应该自己进行测试。 - MAChitgarha

2
你测试程序的问题在于,当 printf() 遇到空终止符 \0 时就停止将参数插入 %s 中。因此,在输出中你可能没有注意到 memcpy() 也复制了字符 ch
我看到 GNU glibc-2.24(对于 x86)中,strcpy() 只是调用了 memcpy(dest, src, strlen(src) + 1)

1

printf("%s",...) 在遇到空值时停止打印数据,因此两个输出结果是相同的。

以下代码区分了 strcpymemcpy

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

int main()
{
    char s[5]={'s','a','\0','c','h'};
    char p[5];
    char t[5];
    int i;
    strcpy(p,s);
    memcpy(t,s,5);
    for(i=0;i<5;i++)
        printf("%c",p[i]);
        printf("\n");
    for(i=0;i<5;i++)
        printf("%c",t[i]);

    return 0;
}

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