Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a deep copy of a struct...making a shallow copy of a struct

Tags:

c

struct

There are questions LIKE this one, but they are not similar enough to my specific question FOR ME to pick up on.

My question is about how to make a deep copy of a struct with pointers as members and how to make a SHALLOW copy of a struct with pointers as members. And then, just for reference, how to make a a deep copy of a struct WITHOUT pointer members and how to make a shallow copy of a struct WITHOUT pointer members (not sure if that last one makes sense).

Let's say we have this:

typedef struct Student
{
    char* first_name; 
    char* last_name; 
    int grade;
    long id;
} Student;

Here is a generic function I made to create a student (the header is being difficult to format):

Student* create_student(const char* first_name, const char* last_name, int grade,long id)

{

   Student *newStudentp = (malloc(sizeof(Student)));

   newStudentp -> last_name = (malloc((strlen(last_name) + 1)  * sizeof(char)));
   newStudentp -> first_name = (malloc((strlen(first_name) + 1)  * sizeof(char)));

   strncpy(newStudentp -> first_name, first_name, strlen(first_name) + 1);
   strncpy(newStudentp -> last_name, last_name, strlen(last_name) + 1);

   newStudentp -> grade = grade;
   newStudentp -> id = id;


   return newStudentp;
}

My attempt to make a deep and a shallow copy;

int main()
{
    Student *s1 = create_Student("Bo","Diddly", 100, 221);
    Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
    memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2?
    return 0;
}

For deep copies of structs with pointer members I know we must make OUR OWN copy function that does something sensible with pointers. What that sensible thing is...I'm not sure...so here is my attempt at this DEEP copy.

void copy_Student(Student *s1, Student *s2)
{
   s2 -> grade = s1 -> grade;
   s2 -> id = s1 -> id;
   s2 -> first_name = s1 -> *first_name;
   s2 -> last_name = s1 -> *last_name;

}

The other part of my question (structs WITHOUT pointers as members) can probably just be explained verbally.

EDITED AFTER READING HELPFUL COMMENTS:

Shallow copy: memcpy(s2,s1,sizeof(Student));

Deep copy:

void free_student(Student* stu)
{
    free(stu -> first_name);
    free(stu -> last_name);
}

void copy_Student(Student *s1, Student *s2)
{
    s2 -> grade = s1 -> grade;
    s2 -> id = s1 -> id;
    s2 -> first_name = strdup(s1 -> first_name);
    s2 -> last_name = strdup(s1 -> last_name);
}
like image 829
Phil Avatar asked Aug 02 '11 11:08

Phil


People also ask

How do you make a shallow copy?

A shallow copy can be made by simply copying the reference. The above code shows shallow copying. data simply refers to the same array as vals. This can lead to unpleasant side effects if the elements of values are changed via some other reference.

What is the difference between a shallow copy and deep copy?

In Shallow copy, a copy of the original object is stored and only the reference address is finally copied. In Deep copy, the copy of the original object and the repetitive copies both are stored.

Can we copy one structure to another structure?

If the structures are of compatible types, yes, you can, with something like: memcpy (dest_struct, source_struct, sizeof (*dest_struct)); The only thing you need to be aware of is that this is a shallow copy.

Does a copy constructor make a shallow or deep copy?

The default copy constructor and assignment operator make shallow copies. A deep copy copies all fields, and makes copies of dynamically allocated memory pointed to by the fields.


1 Answers

The code you have listed as making a shallow copy isn't; it will actually smash the stack and probably crash the program.

Student *s1 = create_Student("Bo","Diddly", 100, 221);
Student *s2 = create_Student("Leeroy","Jenkins",50,1337);
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2?

If you had the size right, that would be the same as s2 = s1;. But since you have the size wrong, it is copying too much and will overwrite whatever is in memory after s2. To do a real shallow copy, leave off the &:

memcpy(s2,s1,sizeof(Student)); //shallow copy of s1 INTO s2

The code you have for a deep copy is similarly wrong, but you're on the right track. The basic idea behind a deep copy is that you have to copy each field; for non-pointer types this is the same as a shallow copy, but for pointers you have to do something smarter. The code you posted, however, isn't doing that. Try this instead.

void copy_Student(Student *s1, Student *s2)
{
    s2 -> grade = s1 -> grade;
    s2 -> id = s2 -> id;
    s2 -> first_name = strdup(s1 -> first_name);
    s2 -> last_name = strdup(s1 -> last_name);
}

Note that to avoid memory leaks, you would also need to free the old names from s2 before assigning the new copies, make a free_Student function that would free these names, and also make sure that create_Student copies the names in the first place (or else include "should free" flags so you don't have to copy literal strings).

Now, for a struct without pointers (or other reference types), there is no difference between a deep and a shallow copy because the data structure it itself shallow.

like image 99
Anomie Avatar answered Sep 17 '22 12:09

Anomie