结构体的初步认识以及其内存的计算

简介: 结构体的初步认识以及其内存的计算

前言


我们知道,通过不同的数据类型我们可以表达不同意义的数据,如长度宽度面积只需要定义一个 int 类型的数据就可以符合大部分的需求。但是,有些东西自存在就是一种集合体,如一个人(他有身高、体重、姓名、爱好等等)一本书(有内容、价格、作者、出版社等等)。如果我们要表达这样的一个存在,以以前的数据结构便无法准确地将其表达。便存在一种拥有多种数据的集合,便叫作结构体。

结构体的定义


image.png

image.png

image.png

 这样子便是一个结构体在函数外部的声明,我们可以在函数外定义全局变量,也可以在函数内定义局部变量。不仅如此还有另一种写法叫做匿名结构体类型,就是在声明是时候不加上结构体标签,但是要在结尾加上定义变量的名称。

image.png

这样写的有一个不利因素就是,在函数之中要使用的时候定义了几个结构体变量就只能使用几个该结构体。

这时候我们想到,如果这样定义了两个结构体,他们的内容完全一样,那这两个结构体是等价的吗?

01f4c8c8f7c84ab19df50f5f1b43b560.png

image.png

运行起来编译器就报错了,即便是内部定义的内容完全一样,但是从编译器的视角来说,这两个结构体并不是同一类型的东西。

结构体的自引用


当我们想要在一个结构体中再包含一个同类型的结构体。

image.png

如此,便会看到编译器给我们报了错误,这个语法本身就是错误的,况且当一个结构体类型内部包含了另一个结构体类型,如此一环套一环,这样我们便无法计算这个结构体的具体大小了。

正确定义的方式应该是这样子,next 表示指向结构体的结构体指针,如此便可以正确定义。

image.png

结构体的初始化


定义完结构体,如果不进行初始化也无法使用。结构体的初始化也十分地简单,只需要在主函数中定义是在后面用大括号进行初始化。6cdc7970f8fa4ac2b2285c4ec979fb63.png

也可以在定义结构体是直接进行初始化,最终的结果都是一样,只不过前者属于局部变量而后者属于全局变量。

1c92e74fdcf4408284bcb3e6990592c8.png

但是我们是可以在一个结构体中嵌套调用另外一个结构体的。

image.png

在定义如此结构体的时候也需要嵌套使用两个{ } ,第一个大括号表示我们对所定义的这个结构体也就是 s 进行初始化,第二个大括号则表示对内部嵌套调用的结构体进行初始化。

image.png

结构体内存的计算


我们来看这串代码,我们定义了两个结构体变量,内容上的区别只有不同数据类型的排放顺序不同,但是这两个结构体的所占内存的大小好像有所不同。

c4ccb21cc0594a54b1e95201cf719e28.png

image.png

从结果上看,两个结构体所占的内存并不相同。为什么会出现这种情况呢?我们需要了解结构体内存补齐的机制。


1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。(VS中默认的值为8)

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。


之所以存在内存补齐的机制,是为了保证在读取的时候可以完整地读取每个数据,因而对内存进行的修饰。即耗费了内存但是大大地增加了代码运行的速率。


既然已经知道了内存补齐的规律,那我们来分析一下上面的代码。c1由于只有一个字节因此刚开始对齐于与结构体变量偏移量为0的地址处,第二个数据为 int 类型的数据,根据规律其他成员变量要对齐到对齐数的整数倍的地址处,而 int 类型数据的对齐数为4,因此 i 应该对齐到偏移为4的位置。第三个数据类型为 char 对齐数为 1 因而直接对齐于偏移为8的位置,这还没完,结构体总大小为最大对齐数的整数倍。目前位置所占大小为9,最大的对齐数为4,所以要再次进行补齐。即最后的内存大小为12。

image.png

同理,第二个结构体,用同样的方法进行推理便可以得到下面的结果。所以总的内存便占了8个字节。

image.png

如果喜欢本篇文章就留下个赞吧,关注博主不迷路,也欢迎大家在评论区留言讨论,谢谢大家。


目录
相关文章
|
5月前
|
存储 安全 数据库
阿里云服务器计算型、通用型、内存型主要实例规格性能特点和适用场景汇总
阿里云服务器ECS计算型、通用型、内存型规格族属于独享型云服务器,在高负载不会出现计算资源争夺现象,因为每一个vCPU都对应一个Intel ® Xeon ®处理器核心的超线程,具有性能稳定且资源独享的特点。本文为大家整理汇总了阿里云服务器ECS计算型、通用型、内存型主要实例规格族具体实例规格有哪些,各个实例规格的性能特点和主要适用场景。
阿里云服务器计算型、通用型、内存型主要实例规格性能特点和适用场景汇总
|
25天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
88 13
|
25天前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
54 11
|
25天前
|
编译器 Go
探索 Go 语言中的内存对齐:为什么结构体大小会有所不同?
在 Go 语言中,内存对齐是优化内存访问速度的重要概念。通过调整数据在内存中的位置,编译器确保不同类型的数据能够高效访问。本文通过示例代码展示了两个结构体 `A` 和 `B`,尽管字段相同但排列不同,导致内存占用分别为 40 字节和 48 字节。通过分析内存布局,解释了内存对齐的原因,并提供了优化结构体字段顺序的方法,以减少内存填充,提高性能。
39 3
|
1月前
|
存储 Java 程序员
结构体和类的内存管理方式在不同编程语言中的表现有何异同?
不同编程语言中结构体和类的内存管理方式既有相似之处,又有各自的特点。了解这些异同点有助于开发者在不同的编程语言中更有效地使用结构体和类来进行编程,合理地管理内存,提高程序的性能和可靠性。
26 3
|
1月前
|
存储 缓存 Java
结构体和类在内存管理方面的差异对程序性能有何影响?
【10月更文挑战第30天】结构体和类在内存管理方面的差异对程序性能有着重要的影响。在实际编程中,需要根据具体的应用场景和性能要求,合理地选择使用结构体或类,以优化程序的性能和内存使用效率。
|
1月前
|
存储 缓存 算法
结构体和类在内存管理方面有哪些具体差异?
【10月更文挑战第30天】结构体和类在内存管理方面的差异决定了它们在不同的应用场景下各有优劣。在实际编程中,需要根据具体的需求和性能要求来合理选择使用结构体还是类。
|
5月前
|
存储 缓存 安全
阿里云服务器实例规格选择参考:经济型、通用算力型、计算型、通用型、内存型区别
当我们在通过阿里云的各种活动选择云服务器实例规格的时候会发现,相同配置的云服务器往往有多个不同的实例可选,而且价格差别也比较大,这会是因为不同实例规格的由于采用的处理器不同,底层架构也有所不同(例如X86 计算架构与Arm 计算架构),因此不同实例的云服务器其性能与适用场景是有所不同。目前阿里云的活动中,主要的实例规格可分为经济型、通用算力型、计算型、通用型、内存型,对于很多初次接触阿里云服务器的用户来说,了解他们之间的差别就是比较重要的了,下面小编来为大家简单介绍下它们之间的区别。
阿里云服务器实例规格选择参考:经济型、通用算力型、计算型、通用型、内存型区别
|
4月前
|
存储 Go
Go 内存分配:结构体中的优化技巧
Go 内存分配:结构体中的优化技巧
|
5月前
|
设计模式 并行计算 安全
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
52 0