Van Tr
Van Tr

Reputation: 6121

Why struct shallow copy does not work?

I'm testing shallow copy for struct with this code:

#include "stdio.h"
#include "conio.h"

int main() {

    struct str {
        char * name;
        int value;
    };

    struct str str_1 = {"go", 255};
    struct str str_2;

    str_2 = str_1;

    str_1.name = "back";

    printf("%s\n",str_1.name);
    printf("%s\n",str_2.name);

    printf("\n");
    system("pause");
    return 0;
}

I expected the result should be:

back 
back

But it was:

back
go

Edit: I expected that because with shallow copy, str_1.name and str_2.name should always point to same place.

Edit: And with dynamic allocation, I got what I expected:

#include <stdio.h>
#include <conio.h>
#include <string.h>

int main() {

    struct str {
        char * name;
        int value;
    };

    struct str str_1; 
    struct str str_2;

    str_1.name = (char*) malloc(5);
    strcpy(str_1.name,"go");

    str_2 = str_1;

    strcpy(str_1.name,"back");

    printf("%s\n",str_1.name);
    printf("%s\n",str_2.name);

    printf("\n");
    system("pause");
    return 0;
}

The result is:

back 
back

What was I misunderstand here ?

Upvotes: 2

Views: 148

Answers (3)

James Greenhalgh
James Greenhalgh

Reputation: 2491

Take a piece of paper and draw what you think is happening at each step slowly, and this should become clear.

Let's draw struct str as so:

---------------------
| const char * name |
---------------------
| int value         |
---------------------

And let's denote a string at address 0xabcdef10 as so:

--0xabcdef10---------------------
|  "string\0"                   |
---------------------------------

So, when we initialise str_1, we need some memory location which will hold "go", lets call that 0xaaaaaa00

--0xaaaaaa00---------------------
|  "go\0"                       |
---------------------------------

Then we initialise str_1 with a pointer to that:

struct str str_1 = {"go", 255};

--str_1---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255                |
----------------------------------

Now we take a shallow copy of str_1, and call it str_2:

--str_2---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255                |
----------------------------------

Next we execute str_1.name = "back";. As before, we first want to create the new string. Lets put that at 0xbbbbbb00:

--0xbbbbbb00---------------------
|  "back\0"                     |
---------------------------------

Then we assign it to str_1.name, so str_1 now looks like:

--str_1---------------------------
| const char * name = 0xbbbbbb00 |
----------------------------------
| int value = 255                |
----------------------------------

Note that we haven't changed str_2.

So, when we look at our final "memory", we see:

--0xaaaaaa00---------------------
|  "go\0"                       |
---------------------------------
  ....

--0xbbbbbb00---------------------
|  "back\0"                     |
---------------------------------
  ....
--str_1---------------------------
| const char * name = 0xbbbbbb00 |
----------------------------------
| int value = 255                |
--str_2---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255                |
----------------------------------

So str_1 points at the new string, and str_2 points at the old string.

In case you describe as dynamic, you never update the pointers in the struct, you could go through the same exercise to draw out what happens to memory in that case.

Upvotes: 2

Lundin
Lundin

Reputation: 214395

str_2 = str_1; makes a hard copy of the struct itself. For example the value member will be unique for every struct.

But you got a soft copy of any pointer members, since the copy does not affect the pointed-at data of any pointer. Meaning that after the copy, the name pointer of both str_1 and str_2 points at the literal "go".

And then str_1.name = "back"; only changes where str_1.name points at. It doesn't change where str_2.name points at.

When you used malloc and strcpy, you change the pointed-at data and get a complete hard copy of everything.

Upvotes: 1

Bathsheba
Bathsheba

Reputation: 234785

str_2 = str_1; did take a shallow copy.

But that doesn't mean that that any subsequent alteration to what name points to in str_1 will be automatically reflected in str_2.

(Really you should use const char* as the string type as you are assigning read-only string literals).

Upvotes: 2

Related Questions