将不同类型的值存储在一起构成结构。
在C语言中,有数组和结构两种聚合数据类型。聚合数据类型指的是能够同时存储一个以上的单独数据。
数组是相同类型的元素的集合,其每个元素是通过下标引用或指针间接访问来选择的。
结构也是一些值的集合,这些值称为它的成员,一个结构的各个成员可能具有不同的类型。结构每个成员都有自己的名字,他们通过名字进行访问来选择的。
1.结构声明
在声明结构时,必须列出它所包含的所有成员。这个列表包括每个成员的类型和名字。
struct tag
{member-list
}variablle-list;
举几个例子进行说明:
struct
{int a;char b;float c;
}x;
上面这段代码,声明创建了一个名为x的变量,它包含3个成员:一个整数,一个字符和一个浮点数。
struct
{int a;char b;float c;
}y[20],*z;
上面这段代码,声明创建了两个变量,名为y和z。其中y是一个数组,包含了20个结构。z是一个指针,它指向这个类型的结构。
在此处需注意:变量y、z与变量x是两种不同的类型,即使他们的成员列表完全相同。
这时我们会想:是否某种特定类型的所有结构都必须使用一个单独的声明来创建呢?
事实并不需要如此,标签(tag)字段允许为成员列表提供一个名字,这样它就可以在后续中使用。标签允许多个声明使用同一个成员列表,并创建同一种类型的结构。
举个例子:
struct TEST
{int a;char b;float c;
};
上面这段代码,对结构的成员进行了声明,这个声明把标签TEST和这些成员联系在了一起。这个声明并没有提供变量列表,所有它并没有创建任何变量。
struct TEST x;
struct TEST y[20],*z;
这些声明使用标签TEST创建了3个变量。它创建了和最初的两个例子一样的变量,但存在一个重要的区别——现在的x、y、z都是同一种类型的结构变量。
声明结构时可以使用另一种良好技巧来创建,使用typedef创建一种新的类型,如下面例子:
typedef struct
{int a;char b;float c;
}Test;
这个技巧和声明一个结构标签效果一样。其区别在于Test现在是类型名而不是结构标签,所以在后续的声明如下:
Test x;
Text y[20],*z;
2.结构成员
结构成员可以是标量、数组、指针甚至其他结构。
如下例子:
struct TEST1
{int a[20]; //数组float f; //变量long *p; //指针struct TEST x; //结构变量struct TEST y[20]; //结构数组struct TEST *z; //结构指针
};
3.结构成员的直接访问
结构变量的成员通过点操作符(.)访问的。(点操作符的结合性是从左向右结合)
点操作符接受两个操作数:左操作数是结构体变量的名字,右操作数是需要访问的成员名字。这个表达式的结果就是指定的成员。
以下面这个声明为例:
struct TEST1 test;
名字为a的成员是一个数组,所以表达式test.a就选择了数组a这个成员,这个表达式结果就是这个数组名,可以把它用在任何使用数组名的地方。
成员x是一个结构,所以表达式test.x的结果就是个结构名,可以用于任何使用普通结构变量的地方。
举例几个复杂表达式:
表达式test.x.a就是选择了结构test的成员x(也是一个结构体)的成员a。
表达式test.y[8].c,将这个表达式分解来看,y是一个结构数组,所以test.y是一个数组名,它的值是一个指针常量。对这个表达式使用下标引用操作,test.y[8]将选择一个数组元素。这个数组元素本身是一个结构,所以可以使用另一个点操作符取它的成员之一。如此,表达式test.y[8].c就是选择了结构test中的成员y[8](一个结构体)中的成员c。
4.结构成员的间接访问
如果我们拥有一个指向结构的指针,我们将通过->(箭头操作符)来间接访问该结构。
和点操作符一样,箭头操作符接受两个操作数,其中左边操作数必须是一个指向结构的指针。
箭头操作符对左操作数执行间接访问取得指针所指向的结构,然后和点操作符一样,根据右操作数选择一个指定的结构成员。
假定一个函数的参数是指向结构的指针,如下所示:
void func(struct TEST1 *cp);
如下是结构间接访问:
cp->a; //访问一个数组名
cp->f; //访问结构的浮点数成员
cp->x; //访问一个结构
5.结构自引用
在一个结构内部包含一个类型为该结构本身的成员。
结构自引用声明如下:
struct TEST2
{int a;struct TEST2 *b;int c;
};
或许我们会觉得在结构内部包含一个指向该结构本身的指针有些奇怪,但它事实上所指向的是同一类型的不同结构。在更加高级的数据结构,比如链表和树,都是用这种技巧实现的,每个结构指向链表的下一个元素或树的下一个分枝。
6.结构的初始化
结构初始化和数组初始化很相似。一个位于一堆花括号内部、由逗号分隔的初始值列表可用于结构中各个成员的初始化。这些值根据结构成员列表的顺序写出。
举个例子:
struct INIT_EX
{int a; //整型变量short b[20]; //数组Test c; //结构
}x;x = {10;{0,1,2};{25,‘x’,1.8};}