1、C语言中结构体深浅拷贝问题的来源
如果一个结构体包含指针变量,并在使用结构的过程中进行了动态内存的分配,同时进行了相同类型的结构体的变量之间进行了相互赋值,此时会引发浅拷贝和深拷贝问题。
2、浅拷贝问题
现在我们考虑如下一段代码,首先我们定义了一个结构体Student,并在main函数里面声明了两个结构体变量std1、std2。接着,我们为std1的name,在堆区开辟了一段10字节大小的空间,并把该空间的首地址复制给了name,并通过strcpy函数,复制一个字符串到name所指向的空间区域;为std1的成员变量age赋值为20。最后我们使用std1直接给std2赋值。我们画出该程序所对应的内存模型。
#include#include #include typedef struct Student { char *name; int age; }Student; int main(int argc, char *argv[]) { Student std1; Student std2; std1.name = (char *)malloc(10); std1.age = 20; strcpy(std1.name, "lele"); printf("std1--->name: %s, age: %dn", std1.name, std1.age); //把std1直接赋值给std2,并打印std2的值 std2 = std1; printf("std2--->name: %s, age: %dn", std2.name, std2.age); //释放std1成员name所指向的内存空间 free(std1.name); //可以成功释放空间 //释放std2成员name所指向的内存空间 free(std2.name); //由于指向的空间已经释放,所以不能重复释放 return 0; }
由该程序的内存模型,我们可以看出。std1和std2的成员name,指向同一块内存区域。假设我们使用完std1和std2变量,会释放name所指向的内存空间。首先,我们先释放sdt1.name所指向的内存空间,此时程序不会有任何问题,可以正常释放。然后,我们在释放std2.name指向的内存空间,此时程序会出错。由于,std2.name所指向的内存空间已经释放。
3、深拷贝问题
为了比避免上述问题的发生,对于包含指针变量的结构体,以及该结构体内的指针变量成员并指向动态分配的一段内存空间,我们相互复制的过程中可以使用深拷贝,让我们看下面一段代码。
#include#include #include typedef struct Student { char *name; int age; }Student; int main(int argc, char *argv[]) { Student std1; Student std2; std1.name = (char *)malloc(10); std1.age = 20; strcpy(std1.name, "lele"); printf("std1--->name: %s, age: %dn", std1.name, std1.age); //把std1直接赋值给std2,并打印std2的值 std2 = std1; std2.name = (char *)malloc(10); //为name成员重新分配一段空间 strcpy(std2.name, std1.name); //把std1.name成员指向的字符串赋值给std.name指向的空间 printf("std2--->name: %s, age: %dn", std2.name, std2.age); //释放std1成员name所指向的内存空间 free(std1.name); //可以成功释放空间 //释放std2成员name所指向的内存空间 free(std2.name); //由于指向的不是同一段空间,可以成功释放 return 0; }
我们在把std1复制给std2之后,std2的成员name重新指向了一段新的空间,并把std1.name所指向的空间的内容,赋值给std2.name所指向的空间。
4、总结
对于不包含指针变量的结构体,以及包含指针变量但是该指针变量并不指向一段动态分配的内存空间,在相互赋值的过程不会引发深浅拷贝问题。对于上述可以引发深浅拷贝问题的情况,所谓深浅拷贝,就是在赋值之后,有没有为赋值的变量重新分配空间,并把内容复制到新开辟的空间里面。深浅拷贝问题,在c语言中发生情况并不多见,但是在C++中比较常见,通常通过运算符重载来避免这些问题。
注:由于笔者,能力有限,有什么写的不对的地方,欢迎指出。



