c - Why copy using pointers is not the same as memmove - Stack Overflow

admin2025-04-18  3

Why copy using pointers in loop:

    for (int i = 0; i < size; i++) {
        dst[i] = src[i];
    }

is not the same as memmove?:

    memmove(dst, src, size);

When we have overlap between src and dst?

Why copy using pointers in loop:

    for (int i = 0; i < size; i++) {
        dst[i] = src[i];
    }

is not the same as memmove?:

    memmove(dst, src, size);

When we have overlap between src and dst?

Share edited Jan 30 at 17:17 chux 155k17 gold badges152 silver badges301 bronze badges asked Jan 30 at 11:17 YanirYanir 113 bronze badges 5
  • I suggest you draw two overlapping arrays on paper, and step through the code while following along using the paper. – Some programmer dude Commented Jan 30 at 11:19
  • 1 Because memmove() chooses what direction to use when copying so that you're not copying a copy (of a copy (of a copy (...)). Your loop always copies from low address to high address. See ideone.com/xymcuh – pmg Commented Jan 30 at 11:19
  • 4 @Yanir It is because you have written incorrectly the call of memmove. You need to write memmove(dst, src, size * sizeof( *src )); provided that the value of dst is less than the value of src. – Vlad from Moscow Commented Jan 30 at 11:20
  • 2 Imagine dst=src+1. The loop will plaster the first value over all the rest, while memmove... won't. – teapot418 Commented Jan 30 at 11:22
  • As @VladfromMoscow already pointed out: It matters what dst and src are pointers to. – Ted Lyngmo Commented Jan 30 at 11:37
Add a comment  | 

3 Answers 3

Reset to default 2

Your copying code may change some of the source elements before they are copied. The output of this code:

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


static void Copy(char *dst, const char *src, size_t size)
{
    for (int i = 0; i < size; ++i)
        dst[i] = src[i];
}


int main(void)
{
    char b0[3] = { 'A', 'B', 'C' };
    char b1[3] = { 'A', 'B', 'C' };

    memmove(b0+1, b0+0, 2);
    printf("After memmove: b0[1] = %c, b0[2] = %c.\n", b0[1], b0[2]);

    Copy(b1+1, b1+0, 2);
    printf("After Copy:    b1[1] = %c, b1[2] = %c.\n", b1[1], b1[2]);
}

is:

After memmove: b0[1] = A, b0[2] = B.
After Copy:    b1[1] = A, b1[2] = A.

because, when i is 0, dst[0] is b1[1], so b1[1] is overwritten with 'A' before the loop increments i to 1. Then, when i is 1, src[1] is b1[1], which now contains 'A' instead of its original 'B', so the data copied to dst[1] is 'A' and not 'B'.

When we have overlap between src and dst?

If you want an example:

char str[] = "Hello world"

memmove(str, str + 6, strlen(str + 6) + 1);

It removes "Hello " from the str. Destination and source are overlapping.

Apart from the boring bug memmove(dst, src, size); -> memmove(dst, src, sizeof(*dst) * size);, then:

memmove specifically gives this guarantee (C23 7.26.2.3)

void *memmove(void *s1, const void *s2, size_t n);

The memmove function copies n characters from the object pointed to by s2 into the object pointed to by s1. Copying takes place as if the n characters from the object pointed to by s2 are first copied into a temporary array of n characters that does not overlap the objects pointed to by s1 and s2, and then the n characters from the temporary array are copied into the object pointed to by s1.

Because memmove comes with this extra safety, it is slower than memcpy and should only be used in situations where you know or suspect that objects overlap.

A plain loop as in your example is similar to memcpy, except in your loop you actually can know that dst and src aren't overlapping. memcpy cannot know that internally.

转载请注明原文地址:http://anycun.com/QandA/1744923737a89547.html