Difference between memcpy and memmove

Solved
leoliom Posted messages 187 Status Member -  
leoliom Posted messages 187 Status Member -
Hello, I have read a lot of documents, I have looked at plenty of examples but I cannot understand the overlapping stuff and others. I want to understand so that I can anticipate what the program will display to me.

Configuration: iPad / Chrome 98.0.4758.97

9 answers

jeannets Posted messages 28378 Registration date   Status Contributor Last intervention   Ambassadeur 6 599
 
Hello,

Memcpy is a memory copy to another address, without destroying the original

https://man7.org/linux/man-pages/man3/memcpy.3.html

Whereas Memmove is a memory move, unlike Memcpy, it clears the source..

https://www.man7.org/linux/man-pages/man3/memmove.3.html

The attributes define the source, the destination, and the size of the values being moved or copied...

Of course, to keep everything in sync, you need to know your lesson and the values in motion. Create examples on graph paper..
0
leoliom Posted messages 187 Status Member 2
 
I also read this site but I didn't understand. As you say, the only way to understand is through a diagram, but I'm struggling with that.

Maybe a small example will help me better understand.
0
Dalfab Posted messages 638 Registration date   Status Member Last intervention   102
 
The two functions are only distinguishable in cases of overlap. This occurs when there are elements present in both the source to copy and the destination.
For example, if you want to copy the first 4 elements of the following table into the last 4:
+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+

If you use
memmove()
, you will get the following result (the last 4 receive exactly what was in the first 4)
+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+---+---+

If you use
memcpy()
, this function is a bit "dumb"; it operates quickly but doesn't "think" much! It is likely to give you the following result:
+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 1 | 2 | 3 | 1 |
+---+---+---+---+---+---+---+
This is a guess; try to understand what caused it to fail and attempt to write code that addresses this, or try to write your own
memcpy()
function and see why the end result is not correct.

Therefore, if there is no overlap, the functions are equivalent (but
memcpy()
is faster), whereas if there is overlap, the
memcpy()
function may produce an incorrect result.
0
leoliom Posted messages 187 Status Member 2
 
According to your example:
int tab[10] = {1, 2, 3, 4, 5, 6, 7}; int tab2[10]; strncpy(tab2,tab1,4); memmove(tab + 3, tab2, strlen(tab)) memcpy(tab + 3, tab2, strlen(tab))


Is it correct?

I didn't understand the sentence It's when some elements are both in the source to copy and in the destination.

For example, in your example, there is overlap for which number?
0
Dalfab Posted messages 638 Registration date   Status Member Last intervention   102
 
You indeed did not understand. There is only one array and we make copies within the array. If there are two arrays then
memcpy()
and
memmove()
are indistinguishable.
And
strncpy()
and
strlen()
are functions that apply to strings. Here they are arrays of integers, it has nothing to do with it and these functions do anything in your code!
My example is:
int tab[7] = {1, 2, 3, 4, 5, 6, 7}; memmove( &tab[3], &tab[0], 4*sizeof(int) ); // copy tab[0]tab[1]tab[2]tab[3] into tab[3]tab[4]tab[5]tab[6]. for ( int i = 0 ; i < 7 ; ++i ) printf( "%d ", tab[i] );
0
leoliom Posted messages 187 Status Member 2
 
I think it's good, I've understood the subtlety between the two, it took me a long time to grasp it
Thank you
0
leoliom Posted messages 187 Status Member 2
 
Bonjour,

To understand the operation of
memcpy
and
memmove
, I looked at their implementation in C, but strangely, they don't always do the same thing. For
memmove
, it works, but not
memcpy
.

Example :

 #include <stdio.h> #include <string.h> void * Memcpy(void* dst, const void* src, unsigned int cnt) { char *pszDest = (char *)dst; const char *pszSource =( const char*)src; if((pszDest!= NULL) && (pszSource!= NULL)) { while(cnt) //until cnt { //Copy byte by byte *(pszDest++)= *(pszSource++); --cnt; } } return dst; } int main(void){ char chaine[7] = "aabbcc"; Memcpy(chaine + 2, chaine, 4); printf("%s\n", chaine); return 0; } 
  • Memcpy
    returns
    aaaaaa
    ;
  • memcpy
    returns
    aaaabb
    .


If I take another implementation from the Internet:

 #include <string.h> #include <stdio.h> void myMemCpy(void *dest, void *src, size_t n){ // Typecast src and dest addresses to (char *) char *csrc = (char *)src; char *cdest = (char *)dest; // Copy contents of src[] to dest[] for (int i = 0; i < n; i++) cdest[i] = csrc[i]; } int main(void){ char str1[7] = "aabbcc"; myMemMove(str1 + 2, str1, 4); printf("New string: %s\n", str1); return 0; } 
  • mymencpy
    returns
    aaaaaa
    ;
  • memcpy
    returns
    aaaabb
    .


I don't understand anymore, their implementation in C seemed correct to me. What is wrong? What is missing from these functions for them to do the same job as
memcpy
?
0
mamiemando Posted messages 33228 Registration date   Status Moderator Last intervention   7 940
 
Hello,

What do
memmove
and
memcpy
do?

Generally, you just need to look at what is described in
man memmove
and
man memcpy
(to be typed into Google or a terminal if you are on Linux)
  • memcpy
    copies a block of memory from one address to another address. The target block must be pre-allocated in memory to accommodate the source block; otherwise, you typically get a segmentation fault. The copying is done byte by byte (and as a reminder, an ASCII character (
    char
    ) takes up one byte, which is why this function is quite similar to
    strcpy
    and thus in
    <string.h>
    ): you read the current source byte, copy it into the corresponding target byte, and repeat the operation until the entire block has been processed.
  • Officially,
    memmove
    moves a block of memory from one address to another address. The target block must be pre-allocated in memory to accommodate the source block; otherwise, you typically get a segmentation fault. There is no guarantee on what will remain at the source block level, but most implementations simply leave it as is to improve performance (and for these implementations,
    memmove
    does exactly the same thing as
    memcpy
    when the source and target blocks do not overlap). In these situations,
    memmove
    is preferred for code readability. However, the source block should no longer be read because, depending on the implementation, it may have been reset.


What happens if the blocks overlap?

Now, let's take a closer look at what happens if the source and target blocks overlap. Here, you need to be cautious, as you might fear edge effects (typically if you're writing in the area you're about to read):
  • According to this page,
    memmove
    uses an intermediate buffer to guard against these edge effects.
  • According to this page, this is not the case for
    memcpy
    , so you need to be careful about what you're doing.


Why is there a
strcpy
function and
memcpy
?

There are several reasons, and before starting, it's important to understand how a string is stored in memory. The core issue is that a string can be arbitrarily long (unlike a
uint32_t
, which is defined to be exactly 32 bits, or 4 bytes). How to keep track of the length?

The choice that was made is to mark the string with a terminating character
'\0'
(which corresponds to the
uint8_t
0
). All the
str*
functions (
strcpy
,
strlen
, ...) and
printf
rely on this terminating character to know when to stop. This means that the string
"abc"
is 4 bytes
{'a', 'b', 'c', '\0'}
and not 3 as one might think. This means you must not forget this famous terminating character as soon as you manipulate strings. Without it, the
str*
functions will continue until they (by chance) encounter a byte that equals 0, often outside of an allocated memory area, leading to a segmentation fault.

Returning to
memcpy
, we see that it can reproduce
strcpy
provided you know the length of the string to be copied (including its terminating
'\0'
character).

Since
memcpy
is designed to manipulate an arbitrary block of memory—which is why, in its prototype, the type
const void *
is used for the source block (read-only) and the type
void *
is used for the target block (read-write)—(in particular, something that is not a string and thus not necessarily terminated by
'\0'
), you need to indicate how many bytes to copy. This is the role of its third parameter.

Back to your code

In your case, since you are manipulating strings, it is not enough to just copy the letters for everything to go smoothly; you must ensure that the string you are going to copy or display has its terminating character
'\0'
. This is something guaranteed by
strcpy
, but not by
memcpy
.

Good luck!
0
leoliom Posted messages 187 Status Member 2
 
Ah, so the implementations of these functions are not correct because we don't take into account the terminal character at the end of the string

Should I modify the code so that it adds this character at the end of the copy for it to work?
0
Dalfab Posted messages 638 Registration date   Status Member Last intervention   102
 
>>> So the implementations of these functions are not correct because they do not take into account the terminal character at the end of the string.
No. Did you see anywhere that memcpy() was supposed to add a string terminator?

>> Do I need to modify the code so that it adds this character at the end of the copy for it to work?
No.

The function memcpy(), the function mymencpy(), and the function Memcpy() are all three compliant.
The standard states:
- if there is no overlap, the function must copy (you can check that all three functions perform the copy correctly).
- if there is overlap, the result is completely unpredictable (so the result is entirely arbitrary, it makes no sense to compare results in this case!)

It is entirely possible that the function memcpy() behaves differently if you change the context!
 char str1[7] = "aabbcc"; char str2[7] = "aabbcc"; memcpy(str1 + 2, str1, 4); printf("New string: %s\n", str1); memcpy(str2 + 2, str2, 4); printf("New string: %s\n", str2);
This code can very well return 2 different results with apparently the same input data, or have a different result in debug version and in release version, try it. It is futile to want to reproduce what you see in the case where the function has an undefined result!
0
mamiemando Posted messages 33228 Registration date   Status Moderator Last intervention   7 940 > Dalfab Posted messages 638 Registration date   Status Member Last intervention  
 
To complement what Dalfab said:
  • the
    str*
    functions assume that the memory block to copy is of arbitrary size but can be viewed as a null-terminated string
    '\0'
    ;
  • the
    mem*
    functions do not make any assumptions about a stopping character (which allows for copying any sequence of bytes, but require a size to know when to stop);
  • in any case, these functions should only read and write in memory areas allocated by the program, otherwise a segmentation fault will be triggered.
0
leoliom Posted messages 187 Status Member 2
 
Thank you for all these answers, I understand better now.
0