如何理解结构体的浅拷贝与深拷贝

本文涉及的产品
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时计算 Flink 版,1000CU*H 3个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 结构体的浅拷贝仅复制对象的引用或基本数据类型值,不创建新对象;深拷贝则会递归地复制所有对象及其引用的对象,形成完全独立的新对象。两者主要区别在于是否共享内部对象。
  1. 浅拷贝(Shallow Copy)

    • 定义:浅拷贝是指在拷贝一个结构体时,只是简单地复制结构体中的成员的值。如果结构体的成员包含指针,那么浅拷贝只是复制指针的值,而不是指针所指向的数据。这意味着原始结构体和拷贝后的结构体中的指针成员将指向相同的内存地址。
    • 示例

      #include <stdio.h>
      #include <stdlib.h>
      
      struct MyStruct {
             
          int num;
          int *ptr;
      };
      
      int main() {
             
          struct MyStruct original;
          original.num = 10;
          original.ptr = (int *)malloc(sizeof(int));
          *original.ptr = 20;
      
          struct MyStruct copy = original;
          // 浅拷贝后,copy.ptr和original.ptr指向相同的内存地址
          printf("original.ptr points to %p and copy.ptr points to %p\n", original.ptr, copy.ptr);
          // 修改copy中的数据
          copy.num = 30;
          *copy.ptr = 40;
          // 观察original中的数据变化
          printf("original.num = %d, *original.ptr = %d\n", original.num, *original.ptr);
          free(original.ptr);
          return 0;
      }
      
    • 解释
      • 在这个示例中,定义了一个包含一个整数成员num和一个整数指针成员ptr的结构体MyStruct。首先初始化original结构体,为ptr成员分配内存并赋值。
      • 当进行struct MyStruct copy = original;这一浅拷贝操作时,copy结构体的num成员获得了original.num的值,而copy.ptr获得了original.ptr的值,也就是它们指向了同一块动态分配的内存。
      • 当修改copy.num时,original.num不受影响,因为它们是独立的整数。但是当修改*copy.ptr时,*original.ptr也会改变,因为它们指向相同的内存位置。
      • 最后,只需要释放original.ptr所指向的内存即可,因为copy.ptr指向的是同一块内存。不过这种共享内存的方式可能会导致问题,比如其中一个结构体释放了指针所指向的内存,另一个结构体再访问该指针就会出现错误(悬空指针)。
  2. 深拷贝(Deep Copy)

    • 定义:深拷贝是指在拷贝一个结构体时,不仅复制结构体中的成员的值,还会复制指针成员所指向的数据。这会创建全新的内存空间来存储数据,使得原始结构体和拷贝后的结构体完全独立,对其中一个结构体的修改不会影响到另一个结构体。
    • 示例

      #include <stdio.h>
      #include <stdlib.h>
      
      struct MyStruct {
             
          int num;
          int *ptr;
      };
      
      void deepCopy(struct MyStruct *dest, const struct MyStruct *src) {
             
          dest->num = src->num;
          dest->ptr = (int *)malloc(sizeof(int));
          *dest->ptr = *src->ptr;
      }
      
      int main() {
             
          struct MyStruct original;
          original.num = 10;
          original.ptr = (int *)malloc(sizeof(int));
          *original.ptr = 20;
      
          struct MyStruct copy;
          deepCopy(&copy, &original);
          // 深拷贝后,copy.ptr和original.ptr指向不同的内存地址
          printf("original.ptr points to %p and copy.ptr points to %p\n", original.ptr, copy.ptr);
          // 修改copy中的数据
          copy.num = 30;
          *copy.ptr = 40;
          // 观察original中的数据变化
          printf("original.num = %d, *original.ptr = %d\n", original.num, *original.ptr);
          free(original.ptr);
          free(copy.ptr);
          return 0;
      }
      
    • 解释
      • 在这个示例中,定义了一个函数deepCopy来实现深拷贝。函数接受两个结构体指针,dest为目标结构体指针,src为源结构体指针。
      • deepCopy函数中,首先复制src结构体的num成员的值到dest结构体的num成员。然后为dest结构体的ptr成员分配新的内存空间,并且将src.ptr所指向的数据复制到dest.ptr所指向的新内存空间中。
      • main函数中,通过deepCopy函数进行深拷贝。之后可以看到original.ptrcopy.ptr指向不同的内存地址。
      • 当修改copy结构体中的成员时,original结构体中的成员不会受到影响,因为它们的数据是相互独立的。最后,需要分别释放original.ptrcopy.ptr所指向的内存,以避免内存泄漏。

总的来说,浅拷贝和深拷贝的主要区别在于对指针成员的处理方式。浅拷贝只是简单地复制指针的值,而深拷贝会复制指针所指向的数据,使得两个结构体在内存使用上更加独立。在实际编程中,需要根据具体的需求来选择合适的拷贝方式。如果结构体中的成员没有指针,浅拷贝和深拷贝的效果是一样的。但如果包含指针,就需要谨慎考虑,避免出现悬空指针、内存泄漏等问题。

相关文章
|
Web App开发 数据采集 自然语言处理
python脚本抢各大平台大额优惠卷
python脚本抢各大平台大额优惠卷
434 0
|
Oracle JavaScript 关系型数据库
MySQL8 OCP可以个人报名了,内卷时代考个证提升自己
MySQL8 OCP可以个人报名了,内卷时代考个证提升自己
2567 0
MySQL8 OCP可以个人报名了,内卷时代考个证提升自己
|
资源调度 监控 数据处理
【Flink】Flink集群有哪些角色?各自有什么作用?
【4月更文挑战第18天】【Flink】Flink集群有哪些角色?各自有什么作用?
|
编译器 C++
深拷贝和浅拷贝介绍
这篇文章讨论了C++中的数据拷贝,特别是浅拷贝和深拷贝的概念。对于基本类型和简单对象,拷贝是按位复制,即浅拷贝,类似于`memcpy()`函数的效果。当类包含动态分配的内存或其他资源时,需要显式定义拷贝构造函数以实现深拷贝,确保对象间的独立性。文中通过一个自定义的变长数组类`Array`示例说明了深拷贝的必要性,并展示了不使用深拷贝可能导致的问题。通常,如果类有指针成员,大部分情况需要深拷贝;否则,浅拷贝可能就足够了。文章还提到了在创建对象时需要预处理的情况,如记录对象创建时间或计数,这也需要深拷贝。
321 0
|
12月前
|
敏捷开发 监控 jenkins
自动化测试之美:打造高效的软件质量保障体系
【10月更文挑战第20天】在软件开发的海洋中,自动化测试如同一艘精准的导航船,引领项目避开错误的礁石,驶向质量的彼岸。本文将扬帆起航,探索如何构建和实施一个高效的自动化测试体系,确保软件产品的稳定性和可靠性。我们将从测试策略的制定、工具的选择、脚本的编写,到持续集成的实施,一步步描绘出自动化测试的蓝图,让读者能够掌握这一技术的关键要素,并在自己的项目中加以应用。
151 5
|
12月前
|
存储 Shell 持续交付
长文 | 我如何使用 git
长文 | 我如何使用 git
100 27
长文 | 我如何使用 git
|
12月前
|
Kubernetes Cloud Native 持续交付
云端新纪元:云原生技术重塑IT架构####
【10月更文挑战第20天】 本文深入探讨了云原生技术的兴起背景、核心理念、关键技术组件以及它如何引领现代IT架构迈向更高效、灵活与可扩展的新阶段。通过剖析Kubernetes、微服务、Docker等核心技术,本文揭示了云原生架构如何优化资源利用、加速应用开发与部署流程,并促进企业数字化转型的深度实践。 ####
155 24
|
12月前
|
存储 安全 网络安全
网络安全的屏障与钥匙:漏洞防御与加密技术深度解析
【10月更文挑战第20天】在数字世界的迷宫中,网络安全是守护我们数据宝藏的坚固盾牌和锋利钥匙。本篇文章将带您穿梭于网络的缝隙之间,揭示那些潜藏的脆弱点—网络安全漏洞,同时探索如何通过现代加密技术加固我们的数字堡垒。从基本概念到实战策略,我们将一同揭开网络安全的神秘面纱,提升您的安全意识,保护个人信息不受侵犯。
144 25
|
12月前
|
存储 人工智能 Java
Neo4j从入门到精通:打造高效知识图谱数据库 | AI应用开发
在大数据和人工智能时代,知识图谱作为一种高效的数据表示和查询方式,逐渐受到广泛关注。本文从入门到精通,详细介绍知识图谱及其存储工具Neo4j,涵盖知识图谱的介绍、Neo4j的特点、安装步骤、使用方法(创建、查询)及Cypher查询语言的详细讲解。通过本文,读者将全面了解如何利用Neo4j处理复杂关系数据。【10月更文挑战第14天】
1404 6
|
存储 网络协议 大数据
一文读懂RDMA: Remote Direct Memory Access(远程直接内存访问)
该文档详细介绍了RDMA(远程直接内存访问)技术的基本原理、主要特点及其编程接口。RDMA通过硬件直接在应用程序间搬移数据,绕过操作系统协议栈,显著提升网络通信效率,尤其适用于高性能计算和大数据处理等场景。文档还提供了RDMA编程接口的概述及示例代码,帮助开发者更好地理解和应用这一技术。