Skacc
Skacc

Reputation: 1768

c memcpy struct by value

Im simply trying to copy one struct to another (copy by value, NOT by reference). Here is fully working code

/* memcpy example */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE (80*sizeof(char))

typedef struct {
    char* name;
} person;

int main ()
{
  person p1;
  p1.name = (char*) malloc( SIZE );

  person p2;
  p2.name = (char*) malloc( SIZE );

  // set p1
  strcpy(p1.name, "John");

  // copy p1 > p2
  memcpy ( &p2, &p1, SIZE );

  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  // change p1 only
  printf("Changing p1.name\n");
  strcpy(p1.name, "ONLY p1.name Changed");

  // now, why did p2 change?
  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  free(p1.name);
  free(p2.name);

  return 0;
}

Here is a fiddle http://cpp.sh/57skb

That code outputs

p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: ONLY p1.name Changed (0x791b3cdd6280)

Expected output would be

p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)

Question: why does p2 change?

Note that doing the same thing without struct works as expected: http://cpp.sh/6qevd

Upvotes: 3

Views: 192

Answers (3)

Enno
Enno

Reputation: 1862

If you just copy the struct, then you're overwriting the pointer, not what it points to. What you probably want to do instead of your memcpy is this:

size_t bytes = strlen(p1.name)+1;
p2.name = realloc(p2.name, bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

Here, bytes is the number of characters in the name plus the string nul-terminator, and the call to realloc changes the size of p2.name to match it. Now, guaranteed that there's enough spoace, you can memcpy the first name into the second.

Using realloc here is probably inefficient, because it preserves the original content of p2.name, which we don't need. An alternative would be to free the old string first, before allocating space for the new one:

size_t bytes = strlen(p1.name)+1;
free(p2.name);
p2.name = malloc(bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

Beware that both malloc and realloc can fail, and will return NULL if your program runs out of memory, so it's good practice to always check for that.

Upvotes: 2

Eraklon
Eraklon

Reputation: 4288

When you make that copy then both structure name member will have the same value so they point to the same memory location. Your code does not show this since you does not print the pointer value properly. Try this to see that they are indeed the same

  printf ("p1.name: %s (%p)\n", p1.name, p1.name );
  printf ("p2.name: %s (%p)\n", p2.name, p2.name );

Output

p1.name: John (0x3ee8d60)
p2.name: John (0x3ee8d60)

p2 does not change after strcpy(p1.name, "ONLY p1.name Changed");. Simply p2.name points to this new string also.

Upvotes: 3

0___________
0___________

Reputation: 67476

you need to copy the allocated memory areas not the structs itself

memcpy ( p2.name, p1.name, SIZE );

Upvotes: 1

Related Questions