网站首页 > 技术文章 正文
文章下方附学习资源,自助领取
最近在做通信协议的解析处理、传递分析的时候,总是遇到通信帧中的结构体拷贝等问题,而这些问题也是比较基础又易错的C语言知识。今天,我们探究一下结构体的深拷贝和浅拷贝。
浅拷贝
C语言中的浅拷贝是指在拷贝过程中,对于指针型成员变量只拷贝指针本身,而不拷贝指针所指向的目标,它按字节复制的。
接下来,我们分几种情况举例来看一下。
1、结构体中不存在指针成员变量时
代码如下:
//在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;
}
运行如下:
点击获取1V1嵌入式学习规划,现在还送100G精选学习资料。鍜ㄨ瀛︿範宓屽叆寮忕墿鑱旂綉寮€鍙?
2、结构体中存在指针成员变量时
代码如下:
//在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语言来说,深拷贝浅拷贝的概念我们不需要深究,在进行结构体拷贝的时候,结构体成员是非指针的话,那么直接赋值是没有任何问题的,建议使用这种方式,避免浅拷贝这类不易发现的错误产生。
如果成员有指针类型,我们就需要重写拷贝函数,自己定义拷贝行为了,这一点我们需要尤为注意。
END
文章来源于技术让梦想更伟大 ,作者李肖遥
本文转载自“嵌入式微处理器”,如有侵权,请联系删除
原文链接:C语言结构体成员赋值的深拷贝与浅拷贝
版权声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
猜你喜欢
- 2024-09-12 c++ printf 到 std::cout(c++怎么用printf输出整数)
- 2024-09-12 C 语言未初始化的局部变量是多少?
- 2024-09-12 大话C语言:函数(c语言函数视频讲解)
- 2024-09-12 每日一题||C语言刷题(c语言刷题网)
- 2024-09-12 大话C语言:逗号运算符及运算法优先级
- 2024-09-12 C语言学习篇(14)-----sizeof运算符
- 2024-09-12 C语言 include的用法(c语言include的用法与搭配)
- 2024-09-12 C语言的位运算基本操作演示(c语言位运算的运算规则)
- 2024-09-12 编写一个C程序,输入a,b,c三个值,输出其中最大值
- 2024-09-12 C语言如何实现大数相加(c语言大数相加思路)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)