结构、联合与枚举

C语言除了提供基本的数据类型外,还提供了其他一些高级的数据类型,这其中自然包括结构(struct)、联合(union)与枚举(enum)。所谓结构就是一个复合的数据类型,在里面可以有很多各种类型的成员,然后用一个整体去表达多个集合在一起的数据。而联合和结构基本相同,唯一的区别就是联合中的成员使用的是同一个存储空间。最后,枚举实际上就是把常量符号化组合起来。

结构

先从一个简单的程序说起:

上面这段程序第3-8行声明了一个结构体类型date,第12行定义了一个结构体类型date的变量today,后面采用.运算符对today里面的成员进行访问,同时我们定义了一个指向结构体类型date的指针变量pDate,并将today的地址赋给它,最后我们打印today的各个成员,以及today的地址和today的值。结果如下:

初学者常见的错误就是会忘了第8行结构体声明后面的分号,和本地变量一样,在函数内部声明的结构类型只能在函数内部使用,所以通常在函数外部声明结构类型,这样就可以被多个函数所使用了。声明结构的形式可以有3种,如下:

对于上面的第1和第3种形式,都声明了结构point,但是第2种形式没有声明point,只是定义了两个变量。其中第3种形式同时声明了结构体类型point,并定义了结构体类型point的两个变量p1p2。结构体类型变量的初始化有2种形式,如下:

和数组变量的初始化一样,若未指定成员的值,则默认为0。注意的是,在C++中若以第2种形式初始化,则一定要按顺序且不能有遗漏的指定每个成员的值,否则就会出现错误。要访问整个结构,可以直接用结构变量的名字。但结构也有一些不同于数组的性质,例如,对于整个结构,可以做赋值、取地址,也可以传递给函数参数。如下:

另外,和数组不同的是,结构变量的名字并不是结构变量的地址,必须使用&运算符,如第16行所示。整个结构可以作为参数的值传入函数,这时候其实是在函数内新建一个结构变量,并复制调用者的结构的值,当然,也可以返回一个结构,这与数组完全不同。同样,和别的基本类型一样,结构类型也可以有结构数组,如下:

结构中也可以包含结构,如下:

更进一步的,可以出现结构中的结构的数组。

struct还经常与typedef一起使用,typedef可以用来声明一个已有数据类型的新名字,比如:typedef int Length;,这使得Length成为int类型的别名。这样,Length这个名字就可以代替int出现在变量定义和参数声明的地方了,比如:Length a,b,len; Length numbers[10];。这样可以改善程序的可读性,具体示例如下:

联合

先从一段程序开始:

开始我们定义了联合类型变量CHICHI里面的成员占据同一个存储空间,我们为整形成员i赋值为1234,然后以十六进制循环打印字符数组ch中各个元素的值,结果如下:

这表明成员ch和成员i共用同一块内存空间,同一时间只有一个成员是有效的,union的大小是其最大的成员,另外,我们所使用的CPU是小端的,即低位在前,也可以理解成高高低低,即高位存放在高地址、低位存放在低地址。可以通过上面这种方式得到一个intdouble内部的各个字节,当我们进行文件操作,或者要把一个整数以二进制形式写到一个文件里去时,这便可以成为我们用来做读写的一个中间的媒介。

枚举

我们知道在程序中不应该出现Magic Number,替代的方法就是用符号而不是具体的数字来表示程序中的数字,这称之为常量符号化,但这样的话就会出现一系列定义独立的const int变量,这个时候我们就可以用枚举类型来表示这些独立的变量。枚举是一种用户定义的数据类型,它用关键字enum以如下语法来声明:enum 枚举类型名字 {名字0, ..., 名字n};。枚举类型名字,通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符号,它们的类型是int,值则依次从0到n。如:enum colors {red, yellow, green};,这样我们就创建了3个常量,red的值是0,yellow的值是1,而green是2。当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值名字。另外,声明枚举量的时候可以指定值,如:enum COLOR {RED=1, YELLOW, GREEN=5, BLACK};,这样声明之后,RED的值就是1,YELLOW的值就是2,GREEN的值就是5,BLACK的值就是6。实际上,枚举只是int,如:

运行结果如下:

注意,以上这种做法仅限于C,在C++中则行不通。

最后,虽然枚举类型可以当作类型使用,但是实际上很少用;如果有意义上排比的名字,用枚举比const int方便;枚举比宏好,因为枚举有int类型。



发表评论

电子邮件地址不会被公开。 必填项已用*标注