谢谢观看!希望以下内容帮助到了你,对你起到作用的话,可以一键三连加关注!你们的支持是我更新地动力。
因作者水平有限,有错误还请指出,多多包涵,谢谢!
在自定义的类型中一共有3种: 结构体、联合体、枚举
那么就先让我们了解一下结构体的细节和枚举类型吧。
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是相同类型的变量,也可以是不同类型的变量。成员变量可以是一个或者多个。
数组也是一些值的集合。数组的每个元素只能是相同类型的数据。元素个数可以是一个或者多个。
注意区分数组和结构的不同点和相同点。
1.1.1结构的声明
让我们通过代码来描述一个学生:一个学生具有的属性是年龄、名字、性别、学号等。
1.1.2结构体变量的创建和初始化
结构体变量的创建有2种方式,但是有点小区别:
- 在的时候进行创建结构体变量。此时的变量是全局变量
- 在函数中用结构体类型来创建结构体变量。此时的变量是此时的变量是局部变量
结构体变量的初始化有2种方式,但是也有区别:
- 在结构体变量的创建时,用进行初始化。此时必须严格按声明中成员变量的顺序来初始化
- 用(使用到操作符)来初始化变量。
通过上面学习结构体的知识,让我们写个代码实现一下,创建和初始化,以及打印数据。
补充知识:可以看到红色方框和红色箭头,我们发现此时打印的浮点数类型的数据居然有偏差。其实这就说明了一点:浮点数在内存中有可能是不能精确保存的。
分析一下:对于、我们是可以准确的写成对应的2进制数、,那么对于这样的浮点数,在内存中是可以准确存放相关的值,但是对于,我们是不能完整地写成对应的2进制数据,因为会始终差一些才可以等于,而由于对于浮点数中的相关值的存放限制在位,那么就可能会舍弃掉一部分的位数,导致浮点数在内存中并不是准确保存的。
所以结论是:浮点数在内存中并不是准确保存的。那根据这一点,在我们对浮点数进行比较大小时,我们就不能简单地对2个数据进行 是否相等的判断,而是有一定的误差。
在声明结构时,可以不完全声明
注意:使用匿名结构体类型创建变量就只能在变量列表中创建,而且只能一次,不能在函数中创建变量了
通过上面的两个代码,代码一和代码二,我们可以得出:在匿名结构体类型中,不要用匿名结构体指针去指向匿名结构体变量(2个匿名结构体的成员变量一样)。
在结构中包含一个类型为该结构本身的成员是否可以呢?
比如,定义一个链表的节点(数据结构有关的知识)
在定义一个链表的节点时,上面是错误的。我们换一个角度看,这个结构体类型的大小我们是否可以得出来,通过分析可以知道因为一个结构体中再包含一个同类型的结构体变量,这样会使得结构体的大小无穷大,这是不合理的。
正确的定义如下:
此时结构体的大小是可以计算出来的,=或字节。在代码中,我们是通过结构体指针指向了下一个节点,这样我们就可以对在内存中不是连续存放的数据进行增删查找等操作。
在结构体自引用使用的过程中,夹杂了 对匿名结构体类型重命名,也容易引入问题,看看下面的代码,可行吗?
答案是:不可行的。因为我们使使用对类型重命名为,是先有了才有的,但是我们在声明类型的时候就已经使用了,这是错误的,要搞清楚主和次的关系。
应对写成下面这种:不要将改为了。
首先让我们看一下对齐现象,然后引出对结构体内存对齐的深入理解。
通过上面的代码,可以得出结论:结构体的成员在内存中是存在对齐现象的,称为结构体内存对齐。
补充知识:偏移量是指一个数据和某另一个数据位置的距离,单位是字节。
其实我们是可以通过代码来大概确认一下为什么是和的结果。此时要使用的C语言提供的宏,计算结构体成员相较于结构体变量起始位置的偏移量,头文件。
通过代码,我们可以看出结构体成员相较于结构体变量起始位置的偏移量具体是多少了,那么我们的想法是就可以根据偏移量的大小来画出其结构体成员在内存中的存放形式。对于,可以看到大小为个字节大小,所以对于按我们自己的想法来理解我们就没有疑问为什么是8字节了。
那么让我们再来测试一下
我们发现此时,按我们自己的想法来理解,我们又产生新疑问了,画出成员在内存中的存放为个字节,代码运行的是个字节,那么我们自己的想法其实是不全对的。
至于是为什么?这就需要引出对齐规则。
首先得掌握结构体的对齐规则:
- 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处
- 其他成员变量要对齐到的的地址处。
对齐数 = 编译器默认的⼀个对齐数 与 该成员变量大小的较小值。- VS 中默认的值为 8
- Linux中 gcc 没有默认对齐数,对齐数就是成员自身的大小
- 结构体总大小为最大对齐数的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构
体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
下面给出练习,试试通过规则来写成结构体类型的大小是多少!
下面我自己在纸上写出了解析,但由于不好放在文章里,就生成了个链接
解析练习1的图片
解析练习2的图片
解析练习3的图片
解析练习4的图片
总结:
计算整个结构体的大小时,先将成员存放到实际对齐数的整数倍的偏移量处,存放完所以成员后,再根据(最大对齐数就是实际对齐数中最大的一个)。
特殊:在对特殊成员(在结构体中的结构体)存放时,就只需要找到它自己内部成员中的最大对齐数就是它的实际对齐数。
那么想一想我们在设计结构体的时候,我们如何做到既要满足对齐,又要节省空间的呢?
答案是:让占用空间小的成员尽量集中在一起
和类型的成员一样,但是和所占用的空间不一样,相较于所占空间较小。
这个预处理指令,可以改变编译器的默认对齐数,从而影响到实际对齐数,导致存放到相应偏移量的位置发生改变,使占用空间发生改变。
结论:结构体在对齐方式不合适的时候,我们可以自己更改默认对齐数,但是默认对齐数最好使用2的多少次方
结构体讲完就得讲讲结构体实现位段的能力。
通过代码可以看出,可以在一定程度上减少空间的浪费,因为假如一个变量表示一个人的年龄,设定1-100岁,那么给int变量占4个字节就有点浪费空间了,那么我们可以限制一下。
上面的猜想和代码运行的结果大小为3个字节是一致的,可能猜想正确,我们还可以测试一下
结论:从修改了初始值的常量开始后面的枚举常量表示的数字都递增+1,前面的保持不变。
对比一下代码一和代码二,在我们看代码主函数中的分支语句,发现两个代码的可读性不一样,看我们可以明确知道哪一部分要实现,而中我们是根据打印菜单对应下来才写相应的操作的。
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/9537.html