Why does memcpy into a buffer and a pointer to the buffer work the same?

84 views Asked by At

Say I have the following code:

char buff[100] = {0};
char msg[] = "hello!";

memcpy(buff, msg, sizeof(msg));

OR

memcpy(&buff, msg, sizeof(msg));

Why do the two memcpy lines work exactly the same?

I expected that when &buff is used, it would copy the msg into the memory where the pointer itself that buff decays into is stored, not the memory that that pointer actually points to.

When I imagine the pointers like this:

&buff->buff->buff[0]

I can rationalize why they behave the same. But when I imagine the actual memory like this:

address        | value   | (name)
--------------  --------- ----------------
0x1000         | 'h'     | (buff[0])
0x1001         | 'e'     | (buff[1])
... etc
__________________________________________

0x5000-0x5008  | 0x1000  | (buf - char *)
__________________________________________

0x8000-0x8008  | 0x5000  | (&buf - char**)
__________________________________________

Now I cannot see why the msg is not written at address 0x5000 instead, overwriting the value 0x1000.

2

There are 2 answers

0
Eric Postpischil On BEST ANSWER

C 2018 6.3.2.1 3 says an array is converted to a pointer to its first element except when:

  • it is the operand of sizeof,
  • it is the operand of unary &, or
  • it is a string literal used to initialize an array.

So, in memcpy(&buff, msg, sizeof(msg)), buff is the operand of unary & and is not converted to a pointer. &buff gives a pointer to the array.

In memcpy(buff, msg, sizeof(msg)), buff is converted to a pointer to its first element.

The starting location of the first element and the starting location of the array are the same location. So &buff and buff have the same value, but different types. So data is copied to the same place in both calls.

(Also note that the difference in types becomes irrelevant because the first parameter of memcpy is declared to be void * restrict, so both &buff and buff are converted to the same type before the call.)

3
chux - Reinstate Monica On

Why do the two memcpy lines work exactly the same?

The address of an array and the address of the first element of the array point to the same location.


memcpy(buff, msg, sizeof(msg)); is like memcpy(&buff[0], msg, sizeof(msg)); as the array buff converts to the type and a pointer to the first element of the array in this usage. Then that pointer to the first element of the array is converted to a void *.

So we are really comparing (void *) &buff[0] and (void *) &buff.


I expected that when &buff is used, it would copy the msg into the memory where the pointer itself that buff decays into is stored,

No. &buff is a pointer and the value of that pointer is passed into memcpy(). There is no decay going on with &buff. The unary & operator is one of the exceptions to the rule that arrays decay to pointers to their first element in expressions. The other exceptions are when an array is the operand of the sizeof, typeof, or typeof_unqual operators (as of C23).