Search code examples
cstructdeep-copyshallow-copy

Shallow copy in C


This is my first question.

I am learning C. And I heard about shallow copy. As I understood, shallow copy means that you copy the address of the object instead of its value. This means that every change to the copied object will affect the original object.

#include<stdio.h>

struct Person {
   char *name;
   int age;
};

int main (void)
{
   struct Person p1 = {"jon", 20};
   struct Person p2 = p1;
   p2.name = "mark";
   p2.age = 26;
 
   printf ("%s\n", p1.name); // print 'jon' not 'mark'!
   printf ("%d\n", p1.age); // prinf 20 not 26
   return 0;
}
   

I tried the above code, and I expeted that the modification of 'p2' will affect 'p1'. But the the content of 'p1' remains the same as if I implemented a deep copy.


Solution

  • I tried the above code, and I expeted that the modification of 'p2' will affect 'p1'. But the the content of 'p1' remains the same as if I implemented a deep copy.

    You have indeed performed a shallow copy of p1 onto p2, but that's not what you think it is. Your p1 and p2 are distinct objects with independent members, but pointer members p1.name and p2.name (presently) have the same pointer value, and as long as that is true, if the string to which they both point were modified, then you could observe it through both p1 and p2:

    int main(void) {
       struct Person p1 = {(char[]) {"jon"}, 20};
       struct Person p2 = p1;
    
       // Confirm copying
       printf ("%s\n", p2.name); // prints 'jon'
    
       // Confirm shallowness
       p2.name[0] = 'R';
       printf ("%s\n", p1.name); // prints 'Ron'
       printf ("%s\n", p2.name); // prints 'Ron'
    
       return 0;
    }
    

    For a deep copy, on the other hand, you would need to make an independent copy of that string for p2.name to point to. Then no modification you can make to one object will be visible via the other. Example:

    int main(void) {
       struct Person p1 = {(char[]) {"jon"}, 20};
       struct Person p2 = p1;
       // complete the deep copying:
       p2.name = strdup(p2.name);
    
       // Confirm copying
       printf ("%s\n", p2.name); // prints 'jon'
    
       // Confirm deepness
       p2.name[0] = 'R';
       printf ("%s\n", p1.name); // prints 'jon'
       printf ("%s\n", p2.name); // prints 'Ron'
    
       return 0;
    }
    

    And in this case, that's as deep as you can go, because the objects to which p1.name and p2.name point do not contain any pointers themselves. There is a distinction between shallow and deep copying only for objects that contain pointers.


    It is also possible to take the address of an object, and then modify the object indirectly through that address (a pointer), but that's not any form of copying. Creating a copy implies producing a distinct object, not a mere alias for the original.