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

后端 未结 6 1860
故里飘歌
故里飘歌 2021-02-01 07:46

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

6条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-02-01 08:07

    SLIGHT DISCLAIMER: I'm assuming a 64-bit gcc compiler as far as sizeof() as well as an 8-byte alignment. I also realize this is almost a 7 year old question, but it popped up in my google search as number 1 so I wanted to clarify a few things for others that might stumble upon it. Really I just wanted to comment, but SO requires 50 reputation to do so. So here goes another answer...

    I'm not sure what the original poster's understanding of a pointer is, but I know personally I had to internally stop thinking of them as "pointing" to anything and think of them as a "memory address of" something.

    The code you have listed as making a shallow copy has a subtle (but potentially catastrophic) oversight.

    In your main() function:

    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?
    

    The local (pointer/memory address) variables s1 and s2 are declared (on the stack):

    • Student *s1 (an 8-byte memory address on 64-bit gcc)
    • Student *s2 (an 8-byte memory address on 64-bit gcc)

    s1 and s2 being pointers are memory addresses of student structs which happen to be allocated in heap memory due to the fact that your create_Student() function is using malloc() which allocates memory on the heap (heap meaning it will stick around even after create_Student() exits).

    Putting an ampersand in front of s1 or s2 is like saying: "Give me the address of the address of my Student struct"

    &s1 and &s2 now represent the memory locations (in the stack) of your s1 and s2 pointers (or memory addresses). In other words you are now 2 levels of pointer deep: a pointer to a (stack located) pointer to a (heap located) Student struct.

    By specifying memcpy(&s2,&s1,sizeof(Student)) you have asked memcpy to overwrite the stack pointer s2 with the contents (or address) of stack pointer s1 as well as corrupt 24 more bytes of main()'s stack memory that immediately follows the 8 bytes starting at &s2 with the 24 bytes that immediately follows &s1. So to quote Anomie:

    If you had the size right, that would be the same as s2 = s1;

    So using the same logic of "needing to make a copy of what pointers point to" your copy_Student() DEEP copy might look like:

    // I swapped the s1 and s2 arguments with
    // target and source for clarity as well as their order
    // to more closely mimic memcpy()
    void copy_Student(Student *target, Student *source)
    {
       if (target!=NULL) free_Student(target); // if target is already allocated, free it...
       assert(source != NULL);
    
       target->grade = source->grade;
       target->id = source->id;
    
       target->last_name = (malloc((strlen(source->last_name) + 1)  * sizeof(char)));
       target->first_name = (malloc((strlen(source->first_name) + 1)  * sizeof(char)));
    
       strncpy(target->first_name, source->first_name, strlen(source->first_name) + 1);
       strncpy(target->last_name, source->last_name, strlen(source->last_name) + 1); 
    }
    

提交回复
热议问题