目录
结构体
结构体本质上是一种复杂的数据类型。因为在c语言中,单通过基本数据类型:整形和浮点型来描述数据会过于单薄,所以有了结构体的产生。
1、内容
结构体类型实际上便是将多个基本数据类型合并在一起,组成一个整体的的复杂的数据类型,来完成对一个复杂对象的描述。
2、定义
结构体类型的定义分为结构体的定义和结构体内部成员变量的定义(成员变量的初始化)。
struct student{
char name[9];
char gender[9];
int ID;
int achievement;
};
结构体的定义便形如上述代码,通过struct+结构体名称这样的形式,然后花括号内包含结构体内各成员变量的类型和名称。
我们按照结构体内部成员变量的顺序,依次对其进行赋值,即可完成结构体内成员变量的定义和整体变量的初始化,即边定义边赋值。
struct student student_1 = { "张三", "男", 2020101, 97 };
struct student student_2 = { "小红", "女", 2020102, 98 };
//student student_1 = { "李四", "男", 2020103, 93 };//报错
值得注意的是,上述代码中第三行的处理方式是非法的。因为结构体内成员变量只有在初始化的时候可以通过赋值来完成,定义完毕之后就不能通过赋值来进行整体的成员变量初始化。
或者我们可以采用先定义再赋值的方式来完成。
struct student student_3;
strcpy(student_3.name, "李四");
strcpy(student_3.gender, "男");
student_3.ID = 2020103;
student_3.achievement = 93;
值得注意的是,在结构体内部存在字符类型的成员变量进行初始化时,需要使用strcpy函数来完成,并不能进行直接的赋值。(对于strcpy函数的介绍和使用,可以参考我之前的文章。)
在上述定义过程中,我们发现对于结构体内容进行定义时,每次都需要进行struct student的声明,导致代码内容赘余。所以我们可以采用typedef来对结构体定义新的类型名。
typedef struct student{
char name[9];
char gender[9];
int ID;
int achievement;
}student_t;
对结构体的声明进行这样的修改之后,在后续对结构体内容进行定义时,我们只需要按照这样的方式便可完成。
student_t student_4 = { "小明", "男", 2020104, 89 };
这样就很好避免了struct student多此出现所带来的冗杂情况。
3、大小
我们可以通过编译来对下面代码进行编译,来判断结构体的大小。
student_t student_5;
printf("%d\n", sizeof(student_5));
得到的结果为28,并非简单的结构体内各成员变量的大小之和(9+9+4+4=26)。
这是因为存在结构体的内存对齐情况。那么为什么会出现结构体内存对齐情况呢?
3.1、内存对齐的原因
因为在内存存储完毕后,我们在读取过程中并不是按照一个一个内存单位来读取,而是一般分为内存块来进行一个个读取。
例如存在char类型和int类型一起存储情况,在读取过程中,我们先读取一个字节大小的char变量后,需要先读取int变量的前三个字节然后到下一行去读取它的最后一个字节,再对int变量进行拼接,才能够完整的读取int变量。
这样耗费时间的读取时间显然是我们不愿意看到的,所以我们采用了新的方式来对该情况进行处理。
![](https://img-blog.csdnimg.cn/d073cb58be544c6c85e77b1f836daa03.png)
即对char变量不止分配一个字节空间,而是分配四个字节空间,使得char变量在存储中与int变量的大小对其,这样在读取中便不需要对数据进行复杂的分割和拼接,只需要每次读取四个字节即可完成,大大提高了数据的读取效率。
内存对其原因的总结:1.有些cpu本身的硬件问题,只能读取固定位置的内存,所以要求内存存储必须对其;2.为了减少程序运行时间,提高程序运行效率。(通过增加内存存储空间,提高内存访问效率)
3.2、结构体中的内存对齐规则
- 在任何一个平台下都有一个默认的对齐数,;(vs中默认对齐数字是8)
- 在结构体中每个成员变量都存在自己独立的对齐数,即成员变量类型的大小;
- 实际成员变量的对齐数是成员自己独立的对齐数与默认对齐数中较小的那个;
- 每个成员变量都应该对齐到这个对齐数的整数倍处;
- 结构体的总大小,应该是实际最大对齐数的整数倍大小,不足需要进行补位。
按照上述的规则,我们可以对上述代码的大小进行分析。
char name[9];
对于第一行成员,name的本身大小为9,由于作为第一位元素,不需要考虑对齐情况,所以它在内存中存储占据9个字节,并且位于前9为内存空间。
char gender[9];
对于第二行成员,gender的本身大小为9,结合它本身的char类型大小为1,所以直接跟在name后面进行存储,此时所占字节大小为18;
int ID;
对于第三行成员,ID的本身大小为4,结合它的类型大小为4,即它本身的对其数为4,而vs中默认对齐数为8,二者取其小,所以ID从4的整数倍处开始存储,即需要对18进行补位,ID从20开始存储,存储到24位。
int achievement;
对于第四行成员,同第三行类型,所以需要从4的整数倍开始存储,而现在位于24位,正好满足,所以achievement从24位存储到28。
综上,本结构体的大小为28字节。