C编程中用于复制数据的memcpy、memmove和strncpy之间有什么区别?

798qvoo8  于 2023-05-28  发布在  其他
关注(0)|答案(2)|浏览(135)
#include <stdio.h>
#include <string.h>

int main() {
    char src[19] = "abcdef";

    char *target = src;

    memcpy(target+3,target,5);
    printf("from memcpy  : %s\n", target);

    strncpy(target+3,target,5);
    printf("from strncpy : %s\n", target);

    memmove(target+3,target,5);
    printf("from memmove : %s\n", target);
}
from memcpy  : abcabcde
from strncpy : abcabcab
from memmove : abcabcab

我看到不同的函数名称,但用法是相同的,我在谷歌微软搜索的一些开发人员说,这是弃用和有害的,我想了解这些函数中的哪一个是正确的复制数据在c语言?

fcg9iug3

fcg9iug31#

简单地说:

  1. memmoven字节从src复制到dest
  2. memcpyn字节从src复制到dest,只要两个区域不重叠。
  3. strncpyn字节或最多\0字节从src复制到dest,以先到者为准。(只要两个区域不重叠。)如果需要,它还使用\0将目的地填充到n字符。
    如果你不想考虑所有这些,就总是使用memmove。特别是(正如您可以看到我对它的“简单”描述的长度相对于其他人),strncpy太奇怪和复杂,通常是有用的。
    [脚注:你没有问strlcpy,但它非常有用,并且做了你可能希望strncpy做的事情。
    要演示strncpymemcpy之间的差异:
char a[] = "hello";
char b[] = "world";

strncpy(a, "pq\0rs", 5);

printf("after strncpy: a = %c %c %c %c %c = %s\n",
            a[0], a[1], a[2], a[3], a[4], a);

memcpy(b, "pq\0rs", 5);

printf("after memcpy: b = %c %c %c %c %c = %s\n",
            b[0], b[1], b[2], b[3], b[4], b);

这个打印

after strncpy: a = p q      = pq
after memcpy:  b = p q  r s = pq

请注意,memcpy复制了所有内容,而strncpy只复制了前两个字符pq,然后将其余部分清零。
大多数情况下,源区域和目标区域不重叠。这里有一个他们这样做的例子:

char x[] = "abcdefghi";
memmove(&x[3], &x[0], 6);
printf("after memmove: %s\n", x);

char y[] = "abcdefghi";
memcpy(&y[3], &y[0], 6);
printf("after memcpy:  %s\n", y);

在我的机器上打印:

after memmove: abcabcdef
after memcpy:  abcabcdbc

此代码片段尝试将字符串的前6个字符复制到字符串的最后6个副本之上。使用memmove,这就可以工作了,结果是abcabcdef。但是使用memcpy,我们得到了错误的结果,因为当它试图复制def时,它们已经被abc覆盖了。(实际上,它比这更复杂一点,但希望你能理解。

mv1qrgav

mv1qrgav2#

memcpy和memmove的操作与数据类型无关。Linux手册页:
memcpy()函数将n个字节从内存区域src复制到内存区域dest。内存区域不得重叠。如果内存区域重叠,请使用memmove(3)。
为了解决我明显的矛盾:如果我有int 2,那就是8字节(假设我们不是在一个旧的16位系统上,int是2字节)。请注意当我尝试复制1 int时会发生什么:

char hex(char num) {
    if(num >=0 && num < 10) {
        return '0' + num;
    } else if(num > 9 && num < 16) {
        return (num - 10) + 'a';
    } else {
        return '\0';
    }
}

void dump(void *ptr) {
    // assume 8 bytes
    for(int i = 0; i<8; i++) {
        char* byte = (char *) (ptr + i);
        char high_nibble = (*byte & 0xf0) >> 4;
        char low_nibble = *byte & 0x0f;
        cout << hex(high_nibble) << hex(low_nibble) << "    ";
    }
    cout << endl;
}

int main() {
    int num[2] = {123456, 65536};
    dump(&num);
    memcpy(num, num + 1, 1);
    dump(&num);
}

结果是:

发生了什么事?当我们将指针偏移1(memcpy的第二个参数)时,它指向下一个int,但是当我们指定“1”复制时,它复制了1个字节而不是1个int。我们必须指定sizeof(int)作为要复制的字节数:

memcpy(num, num + 1, sizeof(int));

现在我们得到了我们需要的:

memcpy不允许src和dest重叠。
strncpy类似于memcpy,但用于字符串,如果在遇到指定字节数之前遇到空字符('\0'),则复制结束。

相关问题