结构的声明、访问、自引用
结构
聚合类型能够同时存储超过一个的单独数据,C提供了两种类型的聚合数据类型,数组和结构。数组是相同类型的元素的集合,它的每个元素是通过下标引用或指针间接访问来选择的。结构也是一些值的集合,这些值称为它的成员。但一个结构的各个成员可能具有不同的类型。
数组元素可以通过下标来访问,这是因为数组元素的长度相同。但是在结构中并非如此,由于结构中的成员可能具有不同的长度,因此不能使用下标来访问它们,而应该通过名字进行访问。
结构变量属于标量类型,所以可以像对待其它标量类型那样执行相同的类型操作,结构也可以作为传递给函数的参数,它们也可以作为函数值从函数返回。
相同类型的结构变量之间可以赋值。
结构声明
声明结构的一般形式
struct tag { member-list}variable-list;
成员列表由若干个成员组成, 每个成员都是该结构的一个组成部分,对每个成员也必须作类型说明。
例如:
struct {
int a;
char b;
float c;
}x;
struct {
int a;
char b;
float c;
}y[20],*z;
x是一个结构体变量,y是一个数组,包含了20个结构,z是一个指针,它指向这个类型的结构。
tag字段允许为成员列表提供一个名字,这样它就可以在后续声明中使用,标签允许多个声明使用同一个成员列表,并且创建同一种类型的结构:
struct SIMPLE{
int a;
char b;
float c;
};
这个声明把标签SIMPLE和这个成员列表联系在一起,该声明并没有提供变量列表,所以它并没有创建任何变量。
使用标签创建变量,注意必须带上struct关键字:
struct SIMPLE x;
struct SIMPLE y[20],*z
声明结构还可以使用typedef创建一个类型别名;
typedef struct {
int a;
char b;
float c;
}Simple;
此时Simple不是一个标签,而是一个类型名,后续的声明可以采用:
Simple x;
Simple y[20],*z;
结构成员的类型可以是标量,数组,指针等等,一个结构的成员可以和其他结构的成员名字相同。
结构成员的访问
结构成员的直接访问
结构体成员变量通过点操作符"."进行访问,点操作符接受两个数,左操作数就是结构变量的名字,右操作数就是需要访问的成员的名字。
结构成员的间接访问
使用指向结构的指针访问结构成员的方式称为结构成员的间接访问。
结构的自引用
在一个结构内部包含一个类型为本身的成员是否合法呢,如:
struct SELF_REF1{
int a;
struct SELF_REF1 b;
int c;
};
这种类型是非法的,因为成员b是一个完整的结构,这种形式的定义将会导致永久的重复下去。
但是在结构中可以包含指向结构本身的指针,如:
struct SELF_REF2{
int a;
struct SELF_REF2 *b;
int c;
};
考虑下面的情况:
struct {
int a;
struct SELF_REF3 *b;
int c;
}SELF_REF3 ;
这个声明的目的是为这个结构创建类型名为SELF_REF3 ,但是,它失败了。类型名直到声明的末尾才定义,所以在结构声明的内部它尚未定义。
解决方案是定义一个结构标签来声明b,如下所示:
struct SELF_REF3 _TAG{
int a;
struct SELF_REF3_TAG *b;
int c;
}SELF_REF3 ;
不完整的声明
偶尔,你必须声明一些相互之间存在依赖的结构。也就是说,其中一个结构包含了另一个结构的一个或多个成员。和自引用结构一样,至少有一个结构必须在另一个结构内部指针的形式存在。
这个问题的解决方案是使用不完整声明,它声明一个作为结构标签的标识符。然后,我们可以把这个标签用在不需要知道这个结构的长度的声明中,如声明指向这个结构的指针。接下来这个声明把这个标签与成员列表联系在一起。
例如:
struct B;
struct A{
struct B *p;
...
}
struct B{
struct A *p;
...
}
在A的成员列表中需要标签B的不完整声明,一旦A被声明后,B的成员列表也可以被声明。