作者 | 李肖遥       责编 | 欧阳姝黎

最近在做通信协议的解析处理、传递分析等问题,总是遇到通信帧中的结构体拷贝等问题,遇到了一些坑,也是比较基础但是易错的C语言知识,一起来探究一下结构体的深拷贝和浅拷贝。

浅拷贝

C语言中的浅拷贝是指在拷贝过程中,对于指针型成员变量只拷贝指针本身,而不拷贝指针所指向的目标,它按字节复制的。我们分几种情况举例子来看一下。

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

代码如下:

//在win10_64位+vs2017
//来源:技术让梦想更伟大
//作者:李肖遥
#include <stdio.h>
typedef struct {char name[64];int age;
}Member;int main(){Member stu1 = { "LiMing", 18 };Member stu2;stu2 = stu1;printf("%s,%d\n", stu2.name, stu2.age);system("pause");return 0;
}

运行如下:

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

代码如下:

//在win10_64位+vs2017
//来源:技术让梦想更伟大
//作者:李肖遥
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char *name;int age;
}Member;int main() {Member Member1, Member2;Member1.name = malloc(sizeof(char) * 64);if (NULL == Member1.name){printf("malloc failed\n");}memset(Member1.name, 0, 64);//strcpy(Member1.name, "LiMing");snprintf(Member1.name, 64, "LiMing");Member1.age = 18;Member2 = Member1;/*拷贝*/snprintf(Member2.name, 64, "LiXiaoYao");Member2.age = 29;printf("%s, %d\n", Member1.name, Member1.age);if (NULL != Member1.name) {free(Member1.name);Member1.name = NULL;}system("pause");return 0;
}

运行如下:

从中我们看到,改变 Member2 的值,Member1 的值也改变了,这说明一片空间被两个不同的子对象共享了,改变一个对象的值另外一个也会随之改变。

我们改变 Member2 写法,申请内存的代码如下:

//在win10_64位+vs2017
//来源:技术让梦想更伟大
//作者:李肖遥
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct {char *name;int age;
}Member;int main() {Member Member1;Member1.name = malloc(sizeof(char) * 64);if (NULL == Member1.name){printf("malloc failed\n");}memset(Member1.name, 0, 64);//strcpy(Member1.name, "LiMing");snprintf(Member1.name, 64, "LiMing");Member1.age = 18;Member Member2;Member2.name = malloc(sizeof(char) * 64);if (NULL == Member2.name){printf("malloc failed\n");}memset(Member2.name, 0, 64);//strcpy(Member2.name, "LiMing");snprintf(Member2.name, 64, "LiXiaoYao");Member2.age = 29;Member1 = Member2;printf("%s, %d\n", Member2.name, Member2.age);if (NULL != Member1.name) {free(Member1.name);Member1.name = NULL;}if (NULL != Member2.name) {free(Member2.name);Member2.name = NULL;}system("pause");return 0;
}

运行如下:

从中我们看到,当数据成员中有指针时,两个类中的两个指针将指向同一个地址,当对象快结束时,会调用两次 free 函数,此时 Member2 已经是野指针(图中有X的错误标志),这个野指针指向的内存空间已经被释放掉,再次释放会报异常错误,要解决这个问题就要涉及到深拷贝了。

深拷贝

深拷贝除了拷贝其成员本身的值之外,还拷贝成员指向的动态内存区域内容,深拷贝会在堆内存中另外申请空间来储存数据。

解决的思路是在释放掉被赋值指针变量的旧指向内存时,重新对其开辟新内存,这种情况下两个结构体中指针地址不同,但是指向的内容是一致的。代码如下:

//在win10_64位+vs2017
//来源:技术让梦想更伟大
//作者:李肖遥
#include <stdio.h>
#include <stdlib.h>typedef struct {char *name;int age;
}Member;int main() {Member Member1;Member1.name = malloc(sizeof(char) * 64);if (NULL == Member1.name){printf("malloc failed\n");}memset(Member1.name, 0, 64);//strcpy(Member1.name, "LiMing");snprintf(Member1.name, 64, "LiMing");Member1.age = 18;Member Member2;Member2.name = malloc(sizeof(char) * 64);if (NULL == Member2.name){printf("malloc failed\n");}memset(Member2.name, 0, 64);//strcpy(Member2.name, "LiMing");snprintf(Member2.name, 64, "LiXiaoYao");Member2.age = 29;if (Member1.name != NULL) {free(Member1.name);Member1.name = NULL;}Member1.name = malloc(strlen(Member2.name) + 1);strcpy(Member1.name, Member2.name);printf("%s, %d\n", Member1.name, Member1.age);if (NULL != Member1.name) {free(Member1.name);Member1.name = NULL;}if (NULL != Member2.name) {free(Member2.name);Member2.name = NULL;}system("pause");return 0;
}

运行如下:

结论

使用C语言来说,深拷贝浅拷贝的概念我们不需要深究,在进行结构体拷贝的时候,结构体成员是非指针的话,那么直接赋值是没有任何问题的,建议使用这种方式,避免浅拷贝这类不易发现的错误产生。

如果成员有指针类型,我们就需要重写拷贝函数,自己定义拷贝行为了,这一点我们需要尤为注意。

☞.NET 开源的免费午餐结束了?☞谷歌中巨大的 SEO 骗局!排名靠前的 HTML 编辑器也不可信
☞“搏一搏,单车变摩托!”华为天才少年耗时四个月,将自行车强势升级为自动驾驶

C 语言结构体成员赋值的深拷贝和浅拷贝相关推荐

  1. C语言 | 结构体成员数组赋值的问题

    C语言只有在定义字符数组的时候才能用"="来初始化变量,其它情况下是不能直接用"="来为字符数组赋值的,之所以不能赋值成功,是因为数组名是一个指针常量,指向固定 ...

  2. c语言结构体成员变量私有化,C语言中结构体变量私有化详解

    C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...

  3. c语言结构体成员变量默认值,C语言结构体要点笔记

    近日,做一个东西却发现自己在C语言,特别是结构体这个知识点上还缺乏认识.所以在学习了网友的分享后,下面在下文记录一些重要的要点吧. 一.struct是一种复合数据类型(这一点很重要,结构体只是一个类型 ...

  4. C语言结构体成员有函数的定义与使用

    ```c#include <stdio.h> typedef int (*FunHandle)(int, int); //定义 指向函数的指针 struct Example {int a; ...

  5. [ C语言 ] 结构体成员定义

    关于bennyhuo不是算命的老师视频的一些感悟. 首先看看这样一段结构体,在这段结构体中定义了一个没有制定长度的数组 typedef struct person {int age;char cons ...

  6. 3.c语言结构体成员内存对齐详解

    一.关键一点 最关键的一点:结构体在内存中是一个矩形,而不是一个不规则形状 二.编程实战 1 #include <stdlib.h> 2 #include <stdio.h> ...

  7. 结构体成员赋值-标记化结构体初始化语法-结构体成员前面加小数点

    指定成员初始化 static struct file_opretions sep4020_key_fops = {.ower = THIS,.read = sep4020_key_read,.open ...

  8. C语言中结构体直接赋值

    FROM:http://codewenda.com/c语言结构体直接赋值/ 在C语言中结构体变量之间可以进行赋值操作吗? 简单结构体的赋值 先说结论:一般来说,C语言中的结构体变量可以用另一个变量对其 ...

  9. c语言的结构体能存放函数吗,在C语言结构体中添加成员函数

    我们在使用C语言的结构体时,经常都是只定义几个成员变量,而学过面向对象的人应该知道,我们定义类时,不只是定义了成员变量,还定义了成员方法,而类的结构和结构体非常的相似,所以,为什么不想想如何在C语言结 ...

最新文章

  1. React router 的 Route 中 component 和 render 属性理解
  2. java相关网络协议无响应_java网络协议有哪些
  3. jquery检验身份证规则
  4. invalid value encountered in double_scalars
  5. C# 3.0新特性系列(1):隐含类型局部变量
  6. python同步oracle_Python cx_Oracle 7引入苏打文档存储
  7. oracle 11g r2 安装过程与卸载详细图解
  8. python类型提示模块包_Python checktypes包_程序模块 - PyPI - Python中文网
  9. Qt总结之十三:QUDPSocket详解
  10. 深度优先搜索与广度优先搜索———模板
  11. (十一)可编辑表格EditorGridPanel
  12. 数据解读 | 川菜出圈只靠辣?你太小瞧川菜了
  13. 80多款装机必备软件,一次搞定
  14. python中文开发环境_python中文开发环境
  15. 关于电气人奋斗的故事
  16. Python爬懂车帝的图片-代码
  17. Matlab编程入门指南:简介、安装、学习路线和几十个编程案例分析。
  18. 读取ES Date从UTC转为北京时间
  19. Opencv判断颜色相似的图片
  20. VMware12+Ubuntu16.04 安装 以及全屏的实现

热门文章

  1. visual studio 安装教程
  2. 后期处理之一:雾蒙蒙风景照片处理技巧
  3. 第k小的数(二分、partition)
  4. 运行Eclipse出现:a java runtime environment(JRE) or java development kit(JDK) must be....
  5. Java后端学习路线(校招前准备)
  6. 一文搞懂List 、ListObject、List?的区别以及? extends T与? super T的区别
  7. NW.js 简介与使用
  8. 06 iOS 关闭侧滑返回
  9. 2015软件工程(1-3班)第四次作业评价
  10. IOS 获取系统通讯录中的联系人信息