文章目录
本章将涉及的内容有:
- 结构体:
- 结构体类型的声明
- 结构的自引用
- 结构体变量的定义和初始化
- 结构体内存对齐
- 结构体传参
- 结构体实现位段(位段的填充&可移植性)
结构体
在初识结构体一文中我们已经简单了解过结构体了,这里将再次学习结构体并了解一些更加深入的内容。
1.1 什么是结构体?
结构体是C语言中一种重要的数据类型,该数据类型由一组称为成员(或称为域,或称为元素)的不同数据组成,其中每个成员可以具有不同的类型。结构体通常用来表示类型不同但是又相关的若干数据。其关键字为struct。
在C语言的实际使用中,我们有各种各样的数据类型,比如char类型、int类型等等,但是如果你要描述一个具有多种类型数据的事物时,那么我们只使用那些单个的数据类型是很困难的。
例如,描述一个学生,我们需要char类型的姓名,需要int类型的年龄,需要float类型的体重和身高。在这种情况下,结构体应运而生,它可以轻松的解决这种问题。
结构体本质上还是一种数据类型,但它可以包括若干个“成员”,每个成员的类型可以相同也可以不同,也可以是基本数据类型或者又是一个构造类型。
1.2 结构体的声明
如何声明一个结构体类型呢?
struct tag
{
member-list;//可定义多种类型变量
}variable-list;//注意此处有分号
//variable-list是变量列表
注意,variable-list是变量列表,变量可以在声明时定义,也可以在用到时定义。结构体的定义和初始化稍后详细再讲。
举例声明一个具体的结构体:例如,声明一个结构体来描述学生。
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
float height;//身高
}; //分号不能丢
声明时也可以不完全声明,比如省略结构体标签:
//匿名结构体类型
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;
//思考在上面代码的基础上,下面的代码是否合法:
p = &x;
//答案是不合法的,因为编译器会把上面的两个声明当成完全不同的两个类型。
当然,这种匿名结构体类型能不用就不用,因为这种结构体只能在它声明时定义变量使用一次,之后再想使用是无法定义变量的,因为没有标签。
1.3 结构体的引用
1.3.1 结构体内引用其他结构体
我们知道,结构体内部成员变量的类型是可以多种多样的,那么我们是否可以在结构体内部再定义结构体变量呢?例如:
struct A
{
int x;
char y;
};
struct B
{
int a;
struct A ba;
};
这样的结构体也是完全没问题的,结构体成员变量可以是结构体类型。
1.3.2 结构体自引用
既然结构体内引用其他结构体类型的成员变量可行,那么我们是否也可以在结构体内部再引用该结构体本身的变量呢?例如:
//这样的代码是否可行?
struct Node
{
int data;
struct Node next;
};
int main()
{
struct Node s;
printf("%d\n", sizeof(s));
return 0;
}
答案是否定的,这样的使用将造成错误!试想如果这样定义了,当我们新定义一个该结构体变量:struct Node s;后,计算这个s的大小时会出现什么情况?会出现死递归的情况,一个结构体变量的大小怎么能是无限大呢?因此这种使用是错误的!
那么结构体是否能自引用呢?答案是肯定的,但是不能像上面一样引用