memcpy、memmove和strncpy在C编程中用于复制数据,它们之间的区别是什么?

huangapple go评论86阅读模式
英文:

What's the difference between memcpy, memmove, and strncpy for copying data in C programming?

问题

从 memcpy  : abcabcde
从 strncpy : abcabcab
从 memmove : abcabcab

对于在C语言中复制数据,我建议使用memcpy

英文:
#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

i see different function names but the usage is the same i have searching on google microsoft some of the developers say that is it deprecated and harmeful i want to understand which one of these functions is the right for copying data in c language ?

答案1

得分: 1

Sure, here's the translation of the provided text:

简而言之:

  1. memmovesrc 复制 n 个字节到 dest
  2. memcpysrc 复制 n 个字节到 dest,前提是这两个区域不重叠。
  3. strncpysrc 复制 n 个字节或遇到 \0 字节为止,以先出现的那个为准。(前提是这两个区域不重叠。)它还使用 \0 填充目标,以确保总共有 n 个字符。

如果你不想考虑这些,就始终使用 memmove。特别是(正如你可以看到,与其他函数相比,我对它的“简单”描述很长),strncpy 太奇怪和复杂,不能普遍使用。

[注:你没有提到 strlcpy,但它非常有用,可以完成你可能希望 strncpy 完成的任务。]

为了演示 strncpymemcpy 之间的区别:

char a[] = "hello";
char b[] = "world";

strncpy(a, "pq
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);
rs", 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
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);
rs", 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 覆盖了。 (实际上比这更复杂一些,但希望你能理解这个概念。)

英文:

Simply:

  1. memmove copies n bytes from src to dest.
  2. memcpy copies n bytes from src to dest, as long as the two regions do not overlap.
  3. strncpy copies n bytes, or up to a \0 byte, from src to dest, whichever comes first. (And as long as the two regions do not overlap.) Also it pads the destination out to n characters using \0, if necessary.

If you don't want to think about all this, just always use memmove. In particular (and as you can see by the length of my "simple" description of it with respect to the others), strncpy is too weird and complicated to be generally useful.

[Footnote: you didn't ask about strlcpy, but it's quite useful, and does what you probably wanted strncpy to do.]

To demonstrate the difference between strncpy and memcpy:

char a[] = "hello";
char b[] = "world";

strncpy(a, "pq
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);
rs", 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
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);
rs", 5); printf("after memcpy: b = %c %c %c %c %c = %s\n", b[0], b[1], b[2], b[3], b[4], b);

This prints

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

Notice that memcpy copied everything, while strncpy only copied the first two characters p and q, and then zeroed out the rest.

Most of the time, the source and destination regions do not overlap. Here's an example where they do:

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);

On my machine this prints:

after memmove: abcabcdef
after memcpy:  abcabcdbc

This code fragment tries to copy the first 6 characters of the string on top of the last 6 copies of the string. Using memmove, this works, resulting in abcabcdef. But using memcpy, we get a wrong result, because by the time it tries to copy the def, they have already been overwritten by abc. (Actually it's a bit more complicated than that, but hopefully you get the idea.)

答案2

得分: 0

memcpy和memmove独立于数据类型操作,但也依赖于它。来自Linux man页面的说明:

memcpy()函数将n个字节从内存区域src复制到内存区域dest。这两个内存区域不能重叠。如果内存区域重叠,请使用memmove(3)。

为了解释我的明显矛盾:如果我有一个int2,那就是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 '
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) {
    // 假设8个字节
    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);
}
'
;
} } void dump(void *ptr) { // 假设8个字节 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); }

结果是:

memcpy、memmove和strncpy在C编程中用于复制数据,它们之间的区别是什么?

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

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

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

memcpy、memmove和strncpy在C编程中用于复制数据,它们之间的区别是什么?

memcpy不允许src和dest重叠。

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

英文:

memcpy and memmove operate dependently AND independently of data type. From the Linux man pages:

> The memcpy() function copies n bytes from memory area src to memory area dest. The memory areas must not overlap. Use memmove(3) if the memory areas do overlap.

To address my apparent contradiction: if I have int2, that is 8 bytes (assuming we're not on an old 16-bit system where int is 2 bytes). Note what happens when I try to copy 1 int:

char hex(char num) {
	if(num &gt;=0 &amp;&amp; num &lt; 10) {
		return &#39;0&#39; + num;
	} else if(num &gt; 9 &amp;&amp; num &lt; 16) {
		return (num - 10) + &#39;a&#39;;
	} else {
		return &#39;
char hex(char num) {
if(num &gt;=0 &amp;&amp; num &lt; 10) {
return &#39;0&#39; + num;
} else if(num &gt; 9 &amp;&amp; num &lt; 16) {
return (num - 10) + &#39;a&#39;;
} else {
return &#39;\0&#39;;
}
}
void dump(void *ptr) {
// assume 8 bytes
for(int i = 0; i&lt;8; i++) {
char* byte = (char *) (ptr + i);
char high_nibble = (*byte &amp; 0xf0) &gt;&gt; 4;
char low_nibble = *byte &amp; 0x0f;
cout &lt;&lt; hex(high_nibble) &lt;&lt; hex(low_nibble) &lt;&lt; &quot;    &quot;;
}
cout &lt;&lt; endl;
}
int main() {
int num[2] = {123456, 65536};
dump(&amp;num);
memcpy(num, num + 1, 1);
dump(&amp;num);
}
&#39;; } } void dump(void *ptr) { // assume 8 bytes for(int i = 0; i&lt;8; i++) { char* byte = (char *) (ptr + i); char high_nibble = (*byte &amp; 0xf0) &gt;&gt; 4; char low_nibble = *byte &amp; 0x0f; cout &lt;&lt; hex(high_nibble) &lt;&lt; hex(low_nibble) &lt;&lt; &quot; &quot;; } cout &lt;&lt; endl; } int main() { int num[2] = {123456, 65536}; dump(&amp;num); memcpy(num, num + 1, 1); dump(&amp;num); }

The result is:

memcpy、memmove和strncpy在C编程中用于复制数据,它们之间的区别是什么?

What happened? When we offset the pointer by 1 (2nd parameter of memcpy), it pointed to the next int, but when we specified "1" to be copied, it copied 1 byte rather than 1 int. We must specify sizeof(int) as our number of bytes to copy:

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

Now we get what we need:

memcpy、memmove和strncpy在C编程中用于复制数据,它们之间的区别是什么?

memcpy does not allow src and dest to overlap.

strncpy is like memcpy but for strings, and if a null character ('\0') is encountered before the number of specified bytes is encountered, the copy ends.

huangapple
  • 本文由 发表于 2023年5月25日 22:34:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76333467.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定