-------------------------------《C和指针》的搬运工-------------------------------
结构基础知识
数据经常以成组的形式存在。例如,雇主必须明了每位雇员的姓名、年龄和工资。如果这些数值能够存储在一起,访问起来会简单一些。但是,如果这些值的类型不同,它们无法存储于同一个数组中。在C语言中,使用结构可以把不同类型的值存储在一起。
一.结构声明
在声明结构时,必须列出结构所包含的所有成员。这个列表包括了每个成员的类型和名字。下面是声明方式:
struct tag { member-list } variable-list;
举个例子:
//这个声明创建了一个名叫x的变量,它包含三个成员:一个整数、一个字符和一个浮点数
struct {
int a;
char b;
float c;
}x;
//这个声明创建了y和z。y是一个数组,它包含了20个结构。z是一个指针,它指向这个类型的结构。
struct {
int a;
char b;
float c;
} y[20], *z;
标签(tag)字段允许为成员列表提供一个名字,这样它就可以在后续的声明中使用。标签允许多个声明使用同一个成员列表,并且创建同一类型的结构。例子如下:
struct SIMPLE {
int a;
char b;
float c;
};
这个声明把标签SIMPLE和这个成员列表联系在一起。该声明没有提供变量表列,所以它并未创建任何变量。下面是如何使用标签创建变量:
struct SIMPLE x;
struct SIMPLE y[20], *z;
现在x、y、z同一种类型的结构变量。
声明结构时可以使用的另一种良好技巧是用typedef创建一种新的类型,如下面的例子所示:
typedef struct {
int a;
char b;
float c;
}Simple;
这个技巧和声明一个结构标签的效果几乎相同。区别在于Simple现在是个类型名而不是个结构标签,后续的声明可能像下面这个样子:
Simple x;
Simple y[20], *z;
提示:
如果你想在多个源文件中使用同一种类型的结构,你应该把标签声明或typedef形式的声明放在一个头文件中。当源文件需要这个声明时可以使用#include指令把那个头文件包含进来。
二.结构成员
前面的声明中只使用了简单类型的结构成员。但可以在一个结构外部声明的任何变量都可以作为结构的成员。尤其是,结构成员可以使标量、数组、指针甚至是其他结构。
struct COMPLEX {
float f;
int a[20];
long *p;
struct SIMPLE s;
struct SIMPLE sa[10];
struct SIMPLE *sp;
};
一个结构的成员名字可以和其他结构的成员的名字相同,所以这个结构的成员a不会与struct SIMPLE s的成员a冲突(成员的访问方式决定的)。
三.结构成员的直接访问
结构变量的成员时通过点操作符(.)访问的。点操作符接受两个操作数,左操作数就是结构变量的名字,右操作数就是需要访问的成员的名字。这个表达式的结果就是制定的成员。例如,考虑下面这个声明
struct COMPLEX comp;
名字为a的成员是一个数组,所以表达式comp.a就选择了这个成员。这个表达式的结果是个数组名,所以你可以把它用在任何可以使用数组名的地方。类似地,成员s是个结构,所以表达式comp.s的结果是个结构名,它可以用于任何可以使用普通结构变量的地方。尤其是,我们可以把这个表达式用作另一个点操作符的做操作符,如(comp.s).a,选择结构comp的成员s(也是一个结构)的成员a。
一个更为复杂的例子。成员sa是一个结构数组,所以comp.sa是一个数组名,它的值是一个指针常量。而:
(comp.sa)[4]
将选择一个数组元素,但这个元素本身是一个结构,所以我们用另一个点操作符取得它的成员之一:
( (comp.sa)[4] ).c
四.结构成员的直接访问
给出一个指向结构的指针,该如何访问这个结构的成员呢?
举个例子,假设一个函数的参数是个指向结构体的指针,如下面的原型所示:
void func( struct COMPLEX *cp );
函数可以使用下面这个表达式来访问这个变量所指向的结构的成员f:
(*cp).f
对指针进行间接访问将访问结构,然后点操作符访问一个成员。
C语言提供了一个更方便的操作符"->"操作符,来完成这项工作。和点操作符一样,箭头操作符接受两个操作数,但左操作数必须是一个指向结构的指针。现在可以向下面这样:
cp->f 、 cp->a 、 cp->s
第1个表达式访问结构的浮点数成员,第二个表达式访问一个数组名,以此类推。