Oussama Teyib
Oussama Teyib

Reputation: 91

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.

Upvotes: 2

Views: 179

Answers (3)

John Bollinger
John Bollinger

Reputation: 181008

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.

Upvotes: 3

Fe2O3
Fe2O3

Reputation: 8354

Here is a real "shallow copy". This example exhibits the consequences you were expecting.

#include <stdio.h>

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

int main( void )
{
    char boy[ 16 ] = "jon"; // must be a "mutable" buffer!

    struct Person p1 = { boy, 20 };
    struct Person p2 = p1;

    printf( "{ %s %d } { %s %d }\n", p1.name, p1.age, p2.name, p2.age );

    strcpy( p2.name, "mark" ); // Where is p2.name pointing??
    p2.age = 26; // change value
 
    printf( "{ %s %d } { %s %d }\n", p1.name, p1.age, p2.name, p2.age );

    return 0;
}
{ jon 20 } { jon 20 }
{ mark 20 } { mark 26 }

It's ALWAYS a good idea to add enough debugging print statements to your code to shine light into the black box. Better is to use a debugger to watch the flow of execution and monitor variables' values.

Upvotes: 1

B Remmelzwaal
B Remmelzwaal

Reputation: 1629

The way you've written it now makes p2 a copy of p1. You want to create a pointer to the address of p1 to modify it.

#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);
   printf ("%d\n", p1.age);
   return 0;

Output:

mark
26

You can use p2->member or (*p2).member to access member variables, since p2 is a pointer and needs to be dereferenced before you can access them.

Upvotes: 0

Related Questions