2

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.

Øuss
  • 55
  • 3
  • 3
    You replicated the `struct` with `struct Person p2 = p1;` but immediately overwrite its members. None of that affects `p1`. – Weather Vane Feb 17 '23 at 00:23
  • 1
    Why do you think you're copying the address of the object? You're not, you've got two structs, one initialized with the same data (a pointer and an integer) as the other. – ShadowRanger Feb 17 '23 at 00:24
  • "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." - that is not how C works. You've gotten struct assignment mixed up with pointer assignment, or with another language's semantics. – user2357112 Feb 17 '23 at 00:24
  • 5
    "*As I understood, shallow copy means that you copy the address of the object instead of its value*." No. Shallow copying means that when you copy the value of an object that includes pointers, you copy the pointers, rather than also copying the objects they point *to*. That is, by the way, exactly what happens when you initialize your `p2` from `p1`. That means that modifications to the *pointed to* objects are visible through both the original object and the copy, but it does not necessarily mean that *all* state is shared between the two. – John Bollinger Feb 17 '23 at 00:24

3 Answers3

3

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

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.

Fe2O3
  • 6,077
  • 2
  • 4
  • 20
0

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.

B Remmelzwaal
  • 1,581
  • 2
  • 4
  • 11