C++ 的浅拷贝和深拷贝(结构体)

拷贝有两种:深拷贝,浅拷贝

浅拷贝:拷贝过程中是按字节复制的,对于指针型成员变量只复制指针本身,而不复制指针所指向的目标

(1)结构体中不存在指针成员变量时

 typedef struct {
char name[];
int age;
}Person; void test005(){ Person stu1 = { "aaa", };
Person stu2;
stu2 = stu1;
printf("%s,%d\n", stu2.name, stu2.age);
} int main(){
test005();
system("pause");
return ;
}

(2)结构体中存在指针成员变量时

 typedef struct{
char *name;
int age;
} Tea; void test006(){
Tea teacher1, teacher2;
teacher1.name = malloc(sizeof(char)* );
memset(teacher1.name, , );
strcpy(teacher1.name, "aaaa");
teacher1.age = ; teacher2.name = malloc(sizeof(char)* );
memset(teacher2.name, , );
strcpy(teacher2.name, "bbbb");
teacher2.age = ; //结构体赋值
teacher1 = teacher2; printf("%s, %d\n", teacher2.name, teacher2.age); if (NULL != teacher1.name){
free(teacher1.name);
teacher1.name = NULL;
}
if (NULL != teacher2.name){
free(teacher2.name);
teacher2.name = NULL;
}
} int main(){
test006();
system("pause");
return ;
}

运行该结构体赋值,出现报错:

浅拷贝存在的问题:当出现类的等号赋值时,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的。但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次free函数,此时teacher2已经是野指针,指向的内存空间已经被释放掉,再次free会报错;另外,一片空间被两个不同的子对象共享了,只要其中的一个子对象改变了其中的值,那另一个对象的值也跟着改变了所以,这时,必须采用深拷贝。

深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。

(3)上述代码的改进

解决办法:释放掉被赋值指针变量的旧指向内存,重新对其开辟新内存存放,主要是为了使两个结构体中name指针地址不同,但是指向的内容一致。

 void test006(){
Tea teacher1, teacher2;
teacher1.name = malloc(sizeof(char)* );
memset(teacher1.name, , );
strcpy(teacher1.name, "aaaa");
teacher1.age = ; teacher2.name = malloc(sizeof(char)* );
memset(teacher2.name, , );
strcpy(teacher2.name, "bbbb");
teacher2.age = ; //结构体赋值
//teacher1 = teacher2;
//-----------------------------------------------
if (teacher1.name != NULL){
free(teacher1.name);
teacher1.name = NULL;
}
teacher1.name = malloc(strlen(teacher2.name) + );
strcpy(teacher1.name, teacher2.name);
//-----------------------------------------------
printf("%s, %d\n", teacher1.name, teacher1.age); if (NULL != teacher1.name){
free(teacher1.name);
teacher1.name = NULL;
}
if (NULL != teacher2.name){
free(teacher2.name);
teacher2.name = NULL;
}
}

​建议:

我们在定义类或者结构体,这些结构的时候,最后都重写拷贝函数,避免浅拷贝这类不易发现但后果严重的错误产生

C语言中结构体的深拷贝和浅拷贝的更多相关文章

  1. C语言中结构体赋值问题的讨论

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  2. C语言中结构体对齐问题

    C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...

  3. C语言中结构体赋值问题的讨论(转载)

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  4. Go语言中结构体的使用-第2部分OOP

    1 概述 结构体的基本语法请参见:Go语言中结构体的使用-第1部分结构体.结构体除了是一个复合数据之外,还用来做面向对象编程.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性. ...

  5. 6. Go 语言中结构体的使用

    1. 结构体的定义格式 在go语言中结果的定义格式如下: 123 type structName struct { filedList} 列子如下: 1234 type Person struct { ...

  6. Go语言中结构体的使用-第1部分结构体

    1 概述 结构体是由成员构成的复合类型.Go 语言使用结构体和结构体成员来描述真实世界的实体和实体对应的各种属性.结构体成员,也可称之为成员变量,字段,属性.属性要满足唯一性.结构体的概念在软件工程上 ...

  7. 关于C语言中结构体中的结构体成员导致的字节对齐问题

    关于结构体的字节对齐是什么,就不赘述,再此附上一篇文章,介绍字节对齐:http://www.linuxsong.org/2010/09/c-byte-alignment/ 这里的结构体字节对齐的数据类 ...

  8. C语言中结构体參数变量的传递

    [文章摘要] 在C语言中,结构体參数变量常常作为函数的參数来进行传递.但假设參数设置不当.会出现内存问题. 本文以实际的程序代码为例.具体地介绍怎样正确地使用结构体參数变量.为相关的开发工作提供了參考 ...

  9. C语言中结构体的访问方法解读

    在C语言中,对结构体的访问一般有两种常规方式:"."访问和"->"访问.那么两者有什么区别呢?对C语言有一定了解的同学应该知道,我们新建一个结构体的时候, ...

随机推荐

  1. jvm虚拟内存分布 与 GC算法

    jvm虚拟内存分布 程序计数器(PC寄存器)(线程私有): 每个线程启动的时候,都会创建一个PC(Program Counter,程序计数器)寄存器. PC寄存器的内容总是指向下一条将被执行指令的地址 ...

  2. Windows DHCP服务器

    DHCP服务器 编辑 动态主机配置协议是一个局域网的网络协议.指的是由服务器控制一段IP地址范围,客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码.首先, DHCP服务器必须是一台安装有 ...

  3. CSS W3C统一验证工具

    CssStats 是一个在线的 CSS 代码分析工具  网址是: http://www.cssstats.com/ 如果你想要更全面的,这个神奇,你值得拥有: W3C 统一验证工具: http://v ...

  4. PHP面向对象魔术方法之__call函数

    l 基本介绍: (1) 当我们调了一个不可以访问的成员方法时,__call魔术方法就会被调用. (2) 不可以访问的成员方法的是指(1. 该成员方法不存在, 2. 成员方法是protected或者 p ...

  5. PAT甲级——A1132 Cut Integer

    Cutting an integer means to cut a K digits lone integer Z into two integers of (K/2) digits long int ...

  6. Spring Boot 实现定时任务的 4 种方式

    作者:Wan QingHua wanqhblog.top/2018/02/01/SpringBootTaskSchedule/ 定时任务实现的几种方式: Timer:这是java自带的java.uti ...

  7. vue 利用intersectionOberver实现全局appear/disappear事件

    搬运自:https://juejin.im/post/5cd10959f265da03a00fe5c6 效果: demo地址: https://codepen.io/deepkolos/pen/OYP ...

  8. 2019-9-2-贡献自己的服务器搭建tor中转

    title author date CreateTime categories 贡献自己的服务器搭建tor中转 lindexi 2019-09-02 12:57:38 +0800 2018-2-13 ...

  9. http及浏览器相关知识点归纳

    http是应用层协议,采用请求/响应模型 1.浏览器地址栏输入URL地址后发生了什么? 浏览器判断地址是否是合理的URL地址,是否是http协议请求,如果是则进入下一步 浏览器对此URL进行缓存检查: ...

  10. 【数位DP】[LOJ10163]Amount of Degrees

    发现自己以前对数位DP其实一窍不通... 这题可以做一个很简单的转换:一个数如果在$b$进制下是一个01串,且1的个数恰好有k个,那么这个数就是合法的(刚开始没判断必定是01串,只判断了1的个数竟然有 ...