当前位置:   article > 正文

自定义类型详解:结构体,枚举_枚举的成员是结构体

枚举的成员是结构体

一:结构体

1.结构体类型的声明

1.1结构体的基础知识
结构体是一些值的集合,这些值称为成员变量
结构体中的每一个成员可以是不同类型的变量。
1.2结构体的声明
在这里插入图片描述
例如我们描述一个学生
在这里插入图片描述

首先 struct表示接下来是一个结构体
stu是结构体的标志,是用来引用该结构体的快速标记
(以我的理解,创建结构体是为了对某一类型进行的一种描述,stu就是这一类型的泛指,就如此处的stu表示的就是学生)
这样,我们就可以创建结构体变量 例如
在这里插入图片描述

接着,用一个花括号,括起结构体成员列表以及成员变量,每个变量的声明按照自己的类型进行。最后用分号来结束描述
最后,花括号的外面要用分号表示该结构体的创建结束
1.3特殊的声明
在声明结构体的时候,可以进行不完全声明,如下,我们的对上文的结构体去掉它的结构体标志,(匿名结构体类型,可以理解为一次性用品)语法上是支持的。但是只能创建全局变量,即只可以在创建结构体的时候创建变量,不可以在main函数内部创建了。


struct 
{
	char name[20];//姓名
	int age;//年龄
	char sex;//性别
}s1,s2;//一定要记得写分号

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意
匿名结构体即便是完全相同,编译器也会认为是两个完全不同的类型,因此指向两个完全相同的匿名结构体的两个指针是不直接可以进行相互赋值操作的

2.结构体的自引用

2.1结构体的自引用

我们为什么要用到结构体自引用呢?例如我们要在内存中存储12345,五个数,我们可以在内存中申请一个连续的空间,将这五个数存放起来(这样的连续存储叫做顺序表),我们要是想找到这五个数从头到尾遍历一遍就好了。
也有可能,这五个数在内存中不是顺序存放的,而是乱序存放的,这个时候我们依然想找到这五个数,它们之间势必要有某种联系可以让他们找到对方,或是找到下一个数,这个时候我们可以用到结构体的自引用。
首先我们可能会想到的是直接在结构体中包含一个本类型的结构体成员列如下图:
在这里插入图片描述
但是这种方法真的可行吗?我们简单看一下这个结构的大小,int->4个字节,但是下面的仍然是一个结构体,该结构体中又包含了一个结构体,就这样无限的嵌套下去,那么此种写法就出现问题。该结构体的大小就是无法确定的。
这个时候,既然是要找到联系,我们就可以想到要用指针,该结构体中,结构体成员正常创建,但是最后创建一个指针变量,该指针变量指向的类型是该结构体,如下图
在这里插入图片描述
注意:我们使用typedef可以给结构体重命名,
在这里插入图片描述
但是此种写法是错误的,因为在创建的时候结构体标志还不叫node,所以不可以这样写
在这里插入图片描述
我们可以换成如下写法
在这里插入图片描述

3.结构体变量的定义和初始化

有了结构体类型,定义变量就直接对照着赋值就可以了,对于结构体的赋值要使用花括号尤其要注意结构体嵌套初始化



struct stu
{
	char name[20];
	int age;
}s1;//声明类型的同时定义变量
struct stu s2;//定义结构体变量s2,此处的s2是全局变量
struct stu s3 = { "xiaowang",20 };//初始化,定义变量的同时赋初值
struct node
{
	int x;
	int y;
}n1={3,4}; //声明类型的同时定义变量并且给变量赋初值

//*结构体嵌套初始化
struct point
{
	int x;
	char y;
	struct node n;
};
struct point p1 = { 1,'a',{5,6} };//结构体的初始化要使用花括号

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

4.结构体内存对齐

现在我们已经掌握了结构体的基本使用了,那么结构体的大小到底是多少呢?
结构体的大小并不是其内部成员的简单相加,而是通过内存对齐来进行计算
首先为什么要内存对齐呢?
1.平台原因:不是所有的硬件平台都可以访问任意地址上的任意数据的,某些硬件平台值可以在某些地址处取得某些特定类型的数据,否则抛出硬件异常。
2.性能的原因:数据结构应当尽可能的在自然边界上对齐,原因是,为了访问未对齐的内存,处理器需要作两次内存访问,但是对于对齐的内存访问仅仅需要一次就够了,可以说,结构体的内存对齐实际上是拿空间来换取时间的做法
那么接下来就要开始进行结构体大小的计算了

首先我们来看一下结构体内存对齐的规则

1.第一成员在于结构体变量偏移量为0的地址处(也就是起始位置)
在这里插入图片描述

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
对齐数=编译器默认的一个对齐数与该成员大小的较小值
(在vs环境中默认对齐数为8,在gcc环境中没有默认对齐数,对齐数就是成员自身的大小)
就是说,从第二个成员变量开始,它在内存中的存放不一定是紧挨着第一个成员存放的,有可能或进行偏移,(这就是内存对齐的过程)那么他要偏移(对齐)到哪里呢?
——>对齐数整数倍地址(也就是由该成员的大小与默认对齐数的较小值的整数倍)处 然后进行存储。
3.结构体总大小最大对齐数(每一个成员变量都有一个对齐数)的整数倍
4.如果是嵌套结构体的情况,嵌套结构体对齐到(自己的最大对齐数)的整数倍处,结构体的整体大小就是所有对齐数的最大值(含嵌套结构体的对齐数)的整数倍

下我们举例来说明一下
在这里插入图片描述
结果如下:在这里插入图片描述

5.偏移量的计算

用offsetof
在这里插入图片描述
头文件:
在这里插入图片描述
具体使用例子如下:
在这里插入图片描述

6.修改默认对齐数

用#pragma pack()来修改

#pragma pack(8)//设置默认对齐数为8
struct s4
{
	char c1;
	struct s3;
	double b;
};
#pragma pack()//取消所设置的默认对齐数,还原为默认

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

结构在对齐方式不合适的时候,我们可以修改默认对齐数

7.结构体

结构体传参最好传结构体的地址
因为结构体传参时,传参时需要压栈的会有时间和空间上的系统开销
如果传递第一个结构体对象时,结构体过大,参数压栈的系统开销就会比较大,回导致性能的下降

8.结构体实现位段(位段的填充&可移植性)

8.1什么是位段
在这里插入图片描述

位段的声明与结构体类似,主要有两点不同之处
1.位段的成员必须是整型家族的成员,如:char,int,unsigned int ,signed int等等
2.位段的成员名后面有一个冒号和一个数字
位段的位指的是二进制位,冒号后面的数字表示的是二进制位数
例如
在这里插入图片描述
8.2位段的内存分配
我们已经知道位段了,那么位段在内存中到底是如何分配的呢?
1.位端的成员可以是整型家族的成员(int unsigned int,char等等)
2.位段的空间上是按照需要4个字节(int)或者是以1个字节(char)的方式来开辟的
(比如上文位段成员都是int类型,我们每次就只开辟四个字节的大小,要是不够,就再开辟四个字节)
3.位段涉及很多不确定的因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
下面我们举例来了解一下位段在内存中的存储方式
在这里插入图片描述
此处说明我们的猜想是正确的,位段的内存分配,在vs中是遵循从右向左使用,分配的内存如果不够用,就会浪费掉。重新开辟一块新的空间。
8.3位段跨平台有可能遇到的问题
1.int位段被当作是有符号数还是无符号数,是不确定的
2.位段中最大位的数目不可以确定(16位机器最大16,32位机器,最大32,如果写成27,在16位机器上会出现问题)
3.位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义
4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余位时,是舍弃剩余位还是利用是不确定的。
因此:和结构相较,位段可以达到同样的效果,还可以横好的节省空间但是,位段会存在不可以跨平台的问题。
8.4位段的应用(有什么用)

二:枚举

1.枚举类型的定义

枚举顾名思义就是指一一列举
把可能的取值一一列举
列如,在现实生活中,一周有七天可以一一列举
一年有十二个月也可以一一列举
在这里插入图片描述
在这里插入图片描述
注意,枚举常量的值默认从0开始,就算赋值,也是从赋值处的值开始往后加一,前面的还是从0开始
在这里插入图片描述

2.枚举的优点

我们都知道,我们可以使用#define来定义变量,为什么还要使用枚举呢?
这里就要讲到枚举的几大优点了
1.增加代码的可读性和可维护性
2.和#define定义的标识符比较 枚举会有类型检查,更加严谨
3.防止命名污染(封装)
4.便于调试
5.使用方便,一次就可以定义多个常量

3.枚举的使用

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/705799
推荐阅读
相关标签
  

闽ICP备14008679号