结构基础知识:聚合数据类型能够同时存储超过一半的单独数据。C提供了两种类型的聚合数据类型,数组和结构体。数组是相同类型的元素的集合,它的每个元素是通过下标引用或指针间接访问来选择的。结构是一些值的集合,这些值称为它的成员,但一个结构的各个成员可能具有不同的类型。
数组元素可以通过下标访问。结构体中的成员可以通过名字访问。
结构并不是一个它自身成员的数组。和数组名不同,当一个结构变量在表达式中使用时,它并不被替换成一个指针。结构变量也无法使用下标来选择特定的成员。
结构变量属于标量类型。结构可以传递给函数的参数,也可以作为返回值从函数返回,相同类型的结构变量相互之间可以赋值。可以声明一个指向结构的指针,取一个结构变量的地址,也可以声明结构数组。
结构声明:在声明结构时,必须列出它所包含的所有成员。这个列表包括每个成员的类型和名字。语法如下:
标签字段允许为成员列表提供一个名字,这样它就可以在后续的声明中使用。标签允许多个声明使用同一个成员列表并且创建同一种类型的结构。如:
该声明并没有提供变量列表,所以它并未创建任何变量。标签标识了一种模式,用于声明未来的变量,但无论是标签还是模式本身都不是变量。
一个结构的成员的名字可以和其他结构的成员名字相同。
结构成员的直接访问:结构变量的成员是通过点操作符 (.) 来访问的。点操作符接受这两个操作数,左操作数就是结构变量的名字,右操作数就是需要访问的成员的的名字。这个表达式的结果就是指定的成员。点操作符的结合性是从左向右。
结构成员的间接访问:->操作符(也称箭头操作符)。和点操作符一样,箭头操作符接受两个操作数,但左操作数必须是一个指向结构的指针。箭头操作符都对左操作符执行间接访问取得指针所指向的结构,然后和点操作符一样,根据右操作数选择一个指定的结构成员。
结构的自引用:一个结构内部可以包含一个指向该结构本身的指针,不能包含该结构自身。该结构本身的指针事实上它所指向的是同一种类型的不同结构。
不完整的声明:声明一个作为结构标签的标识符。然后,可以把这个标识符用在不需要知道这个结构的长度的声明中,如声明指向这个结构的指针。
结构的初始化:结构的初始化方式和数组的初始化很相似。一个位于一对花括号内部、右逗号分隔的初始值列表可用于结构各个成员的初始化。这些值根据结构成员列表的顺序写出。如果初始列表值不够,剩余的结构成员将使用缺省值进行初始化。结构中如果包含数组或结构成员,其初始化方式类似于多为数组的初始化。一个完整的聚合类型成员的初始值列表可以嵌套于结构的初始值列表内部。
C语言没有定义结构和整型值之间的加法运算。
sizeof操作符能够得出一个结构的整体长度,包括因边界对齐而跳过的那些字节。如果必须确定结构某个成员的实际位置,应该考虑边界对齐因素,可以使用offsetof宏(定义于stddef.h)。
如上所示,type是结构的类型,member就是需要的那个成员名。表达式的结果是一个size_t值,表示这个指定成员开始存储的位置距离结果开始存储的位置偏移几个字节。
位段:位段的声明和结构类似,但它的成员是一个或多个位的字段。这些不同长度的字段实际上存储于一个或多个整型变量中。位段的声明和任何普通的结构成员声明相同,但有两个例外。首先,位段成员必须声明为int、signed或unsigned int类型。其次,在成员名的后面是一个冒号和一个整数。这个整数指定该位段所占用的位的数目。
位段是结构的一种,但它的成员长度以位为单位指定。位段声明在本质上是不可移植的,因为它涉及许多与实现有关的因素。但是,位段允许把长度为奇数的值包装在一起节省存储空间。
联合:联合的所有成员引用的是内存中相同的位置。
如果联合的各个成员具有不同的长度,联合的长度就是它最长成员的长度。联合变量可以被初始化,但这个初始值必须是联合第1个成员的类型,而且它必须是位于一对花括号里面。