ChippyZ ChippyZ - 3 months ago 13
C Question

Behavior of struct copying in C

I have been reading a number of questions on this site about how to duplicate structs in C. I've been playing around with some code, trying to understand the differences between 'shallow' copying (where the new struct is simply assigned a pointer to the memory address of the first struct) and 'deep' copying (where the data is copied member-by-member into a new chunk of memory).

I created the following code, assuming that it would show the 'shallow' copying behavior:

#include <stdio.h>

struct tester
{
int blob;
int glob;
char* doob[10];
};

int main (void)
{
//initializing first structure
struct tester yoob;
yoob.blob = 1;
yoob.glob = 2;
*yoob.doob = "wenises";

//initializing second structure without filling members
struct tester newyoob;
newyoob = yoob;
//assumed this line would simply copy the address pointed to by 'yoob'

//printing values to show that they are the same initially
printf("Before modifying:\n");
printf("yoob blob: %i\n", yoob.blob);
printf("newyoob blob: %i\n", newyoob.blob);

//modifying 'blob' in second structure. Assumed this would be mirrored by first struct
newyoob.blob = 3;

//printing new int values
printf("\nAfter modifying:\n");
printf("yoob blob: %i\n", yoob.blob);
printf("newyoob blob: %i\n", newyoob.blob);

//printing memory addresses
printf("\nStruct memory addresses:\n");
printf("yoob address: %p\n", &yoob);
printf("newyoob address: %p\n", &newyoob);

}


Output on running:

Before modifying:
yoob blob: 1
newyoob blob: 1

After modifying:
yoob blob: 1
newyoob blob: 3

Struct memory addresses:
yoob address: 0x7fff3cd98d08
newyoob address: 0x7fff3cd98cb0


Is this code create a deep copy, as it appears, or am I misunderstanding what's happening here?

Answer

The shallow vs. deep copy problem is only relevant to pointers. Given a type struct foo:

struct foo a = /* initialize */;
struct foo b = a;

All the values in a are copied to b. They are not the same variable.

However, with pointers:

struct foo *p = calloc(1, sizeof *p);
struct foo *q = p;

q now points to the same memory as p; no copying has taken place (and you run the risk of a dangling pointer once one gets freed). This is a pointer alias. In order to do a shallow copy, one would do:

struct foo *p = calloc(1, sizeof *p);
/* assign to p's fields... */

struct foo *q = calloc(1, sizeof *q);
*q = *p;

Now q has the same field values as p but points to a different block of memory.

A deep copy requires additional effort; any pointers in the structure must be traversed and have their contents copied as well. See this post for a good explanation.