结构体赋值:浅拷贝与深拷贝
现在我们来研究下结构体赋值。首先,需要介绍下在进行数据拷贝与赋值的时候用到的深拷贝和浅拷贝。
所谓浅拷贝(shallow copy)是指在被拷贝的对象中有指针的情况下,只是将目标指针设置为被拷贝指针的值(地址),而不会为目标指针分配一个新的内存,并把数据从被拷贝指针所指的内存中拷贝到这个内存中来;而深拷贝(deep copy),就是为目标指针申请一个新的内存,然后将数据从被拷贝指针所指的内存中拷贝到这个新申请的内存中来。采用深拷贝的情况下,释放内存的时候就不会出现在浅拷贝时重复释放同一内存的错误。
浅拷贝是系统默认的拷贝方法,而深拷贝需要程序员自己实现。
比如我们定义了2个结构体变量s1,s2。在s1和s2经过初始化之后,在程序运行期间,将s1的值直接赋值给s2:
student s1;
student s2;
…
s2=s1;
这种赋值方式,是否合法呢?
这需要分不同的情况。如果结构体student中没有任何的指针或者数组,没有问题。但是如果有了指针或者数组,就会有问题了。比如说:
typdef struct _struct1
{
int a;
char b;
}struct1;
struct1 s1 = {1, ‘a’};
struct1 s2 = s1;
因为结构体中不包含指针和数组,那么这个赋值是没有任何问题的。但是,考虑下面的结构体定义:
typdef struct _struct2
{
int a;
char *p;
}struct2;
结构体中包含了一个指针成员p。那么试分析下面的代码:
struct2 s1;
s1.a = 10;
s1.p = (char *)malloc(100);
strcpy_s(s1.p,100,”hello world”);
struct1 s2 = s1;
free(s1.p);
s1.p=NULL;
这个时候s2.p所指向的内存已经在执行完free(s1.p)之后就被释放了,因此s2.p就是一个野指针了,因为它指向的指针内存已经被释放掉了。
由于C语言中在进行赋值的时候是浅拷贝,所以,将会使新的结构中的指针指向原来的结构中的同一个地址。一旦原来的结构释放,如果新的结构变量中再次释放,就会出问题。
在C++里重载=操作符并正确的处理了动态分配的内存的情况可以直接使用=号赋值。但C语言里面,一般不建议这样做。必须由程序员自己实现深拷贝:
struct2 s1;
s1.a = 10;
s1.p = (char *)malloc(100);
…
struct1 s2;
s2.a=s1.a;
s2.p=(char *)malloc(100);
memcpy(s2.p,s1.p,100);
free(s1.p);
…
这样即使执行了free(s1.p)之后,也不会对s2.p造成任何的影响。