C语言结构体成员赋值的深拷贝与浅拷贝详解

 更新时间:2022年09月30日 15:49:58   作者:编程小鱼六六六  
C语言中的浅拷贝是指在拷贝过程中,对于指针型成员变量只拷贝指针本身,而不拷贝指针所指向的目标,它按字节复制的。深拷贝除了拷贝其成员本身的值之外,还拷贝成员指向的动态内存区域内容。本文将通过示例和大家详细说说C语言的深拷贝与浅拷贝,希望对你有所帮助

浅拷贝

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

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

代码如下:

#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;
}

运行如下:

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

代码如下:

#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写法,申请内存的代码如下:

#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的错误标志),这个野指针指向的内存空间已经被释放掉,再次释放会报异常错误,要解决这个问题就要涉及到深拷贝了。

深拷贝

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

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

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

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

到此这篇关于C语言结构体成员赋值的深拷贝与浅拷贝详解的文章就介绍到这了,更多相关C语言深拷贝 浅拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++读取访问权限冲突引发异常问题的原因分析

    C++读取访问权限冲突引发异常问题的原因分析

    C语言是一门通用计算机编程语言,广泛应用于底层开发,最近在用C++写代码时经常会遇到“引发了异常: 读取访问权限冲突,所以这篇文章主要给大家介绍了关于C++读取访问权限冲突引发异常问题的相关资料,需要的朋友可以参考下
    2021-07-07
  • C++实现LeetCode(37.求解数独)

    C++实现LeetCode(37.求解数独)

    这篇文章主要介绍了C++实现LeetCode(37.求解数独),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++关键字thread_local学习笔记

    C++关键字thread_local学习笔记

    这篇文章主要为大家介绍了C++关键字thread_local学习笔记,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • OpenCV画任意圆弧曲线

    OpenCV画任意圆弧曲线

    这篇文章主要为大家详细介绍了OpenCV画任意圆弧曲线,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-01-01
  • ipv6实现udp编程示例

    ipv6实现udp编程示例

    这篇文章主要介绍了ipv6实现udp编程示例,需要的朋友可以参考下
    2014-03-03
  • C/C++ 原生API实现线程池的方法

    C/C++ 原生API实现线程池的方法

    线程池,简单来说就是有一堆已经创建好的线程,接下来通过本文给大家介绍C/C++ 原生API实现线程池的方法,感兴趣的朋友跟随小编一起看看吧
    2021-11-11
  • Linux系统下如何使用C++解析json文件详解

    Linux系统下如何使用C++解析json文件详解

    JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。下面这篇文章主要给大家介绍了关于Linux系统下如何使用C++解析json文件的相关资料,需要的朋友可以参考下
    2021-06-06
  • C++实现二分法求连续一元函数根

    C++实现二分法求连续一元函数根

    这篇文章主要为大家详细介绍了C++实现二分法求连续一元函数根,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • C++的数据类型你真的了解吗

    C++的数据类型你真的了解吗

    这篇文章主要为大家详细介绍了C++的数据类型,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • 深入C++可见性与生命期的区别详解

    深入C++可见性与生命期的区别详解

    本篇文章对C++中可见性与生命期的区别进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论