C 编程/高级数据类型
在章节 变量 中,我们了解了基本数据类型。然而,高级数据类型使我们能够在程序中更灵活地管理数据。
结构体是数据类型,由其他数据类型的变量组成(可能包括其他结构体)。它们用于将信息片段分组为有意义的单元,并允许某些其他方式无法实现的构造。在结构体中声明的变量称为“成员”。可以使用struct
关键字定义结构体。例如
struct mystruct {
int int_member;
double double_member;
char string_member[25];
} struct_var;
struct_var
是 struct mystruct
类型的变量,我们在定义新的 struct mystruct
数据类型的同时声明了它。更常见的是,结构体变量在结构体定义之后声明,使用以下形式
struct mystruct struct_var;
通常的做法是创建一个类型别名,这样我们就不必每次都输入“struct mystruct”。C 允许我们使用typedef
语句这样做,该语句为类型指定别名
typedef struct {
// ...
} Mystruct;
struct
本身是一个不完整的类型(因为第一行没有名称),但它被指定为Mystruct
的别名。然后可以使用以下方式
Mystruct struct_var;
可以使用成员访问运算符.
(点号)或间接成员访问运算符->
(箭头)访问结构体变量的成员,如果结构体变量是指针
struct_var.int_member = 0;
struct_var->int_number = 0; // this statement is equivalent to: (*struct_var).int_number = 0;
(指针将在下一章解释。)结构体不仅可以包含自己的变量,还可以包含指向其他结构体的变量。这允许递归定义,当与指针一起使用时非常强大
struct restaurant_order {
char description[100];
double price;
struct restaurant_order *next_order;
};
这是对 链表 数据结构的实现。每个节点(一个餐厅订单)都指向另一个节点。链表在最后一个节点(在我们的示例中,这是最后一个订单)处终止,该节点的next_order
变量被分配为NULL
。
当与typedef
一起使用时,递归结构体定义可能很棘手。不能使用其别名定义在结构体类型内部声明结构体变量,因为在typedef
语句被评估之前,别名定义并不存在
typedef struct Mystruct {
// ...
struct Mystruct *pointer; // Mystruct *pointer; would cause a compile-time error
} Mystruct;
结构体类型的尺寸至少等于所有成员尺寸的总和。但是编译器可以自由地在结构体成员之间插入填充字节,以使成员对齐到某些约束。例如,在许多 32 位体系结构中,包含字符和浮点数的结构体将占用 8 字节。
联合体的定义类似于结构体。两者之间的区别在于,在结构体中,成员占用内存的不同区域,而在联合体中,成员占用内存的相同区域。因此,例如在以下类型中
union {
int i;
double d;
} u;
程序员可以访问u.i
或u.d
,但不能同时访问两者。由于u.i
和u.d
占用内存的相同区域,修改其中一个会修改另一个的值,有时会以不可预测的方式进行。这也是联合体在实践中很少见的主要原因。
联合体的尺寸等于其最大成员的尺寸。
枚举类型是表示标签和整数之间关联的人工数据类型。与结构体或联合体不同,它们不是由其他数据类型组成的。示例声明
enum color {
red,
orange,
yellow,
green,
cyan,
blue,
purple,
} crayon_color;
在上面的示例中,red 等于 0,orange 等于 1,... 等等。可以在整数范围内为标签分配值,但它们必须是字面量。
适用于结构体和联合体的类似声明语法也适用于枚举类型。此外,通常无需关注标签所代表的整数
enum weather weather_outside = rain;
这种特殊的属性使得枚举类型在 switch-case 语句中特别方便
enum weather {
sunny,
windy,
cloudy,
rain,
} weather_outside;
// ...
switch (weather_outside) {
case sunny:
wear_sunglasses();
break;
case windy:
wear_windbreaker();
break;
case cloudy:
get_umbrella();
break;
case rain:
get_umbrella();
wear_raincoat();
break;
}
枚举类型是在 C 中模拟关联数组的简化方法。