在《变量》章节中,我们介绍了基本数据类型。然而,先进的数据类型使我们能够在程序中更灵活地管理数据。

结构体(Structs)

结构体是由其他数据类型的变量(可能包括其他结构体)组成的数据类型。它们用于将信息块组织成有意义的单元,并且允许一些在其他情况下无法实现的结构。结构体中的变量称为“成员”。定义结构体使用 struct 关键字。例如:

struct mystruct {
    int int_member;
    double double_member;
    char string_member[25];
} struct_var;

struct_var 是类型为 struct mystruct 的变量,我们在定义新结构体 mystruct 数据类型时同时声明了它。更常见的做法是,在定义结构体之后声明结构体变量,形式如下:

struct mystruct struct_var;

通常的做法是创建类型别名,这样我们就不必每次都输入“struct mystruct”。C 允许通过 typedef 语句为类型创建别名:

typedef struct {
    // ...
} Mystruct;

结构体本身是一个不完整的类型(因为在第一行没有名称),但是它被别名为 Mystruct。然后可以这样使用:

Mystruct struct_var;

可以使用成员访问运算符(.)来访问结构体变量的成员,或者如果结构体变量是指针,则使用间接成员访问运算符(->,箭头):

struct_var.int_member = 0;
struct_var->int_member = 0; // 此语句等价于:(*struct_var).int_member = 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; 会导致编译错误
} Mystruct;

结构体类型的大小至少是所有成员大小的总和。但编译器可以在结构体成员之间插入填充字节,以将成员对齐到某些约束。例如,包含一个 char 和一个 float 的结构体,在许多 32 位架构中将占用 8 字节。

联合体(Unions)

联合体的定义类似于结构体。两者的区别在于,结构体的成员占用不同的内存区域,而联合体的成员占用相同的内存区域。因此,在下面的类型定义中:

union {
    int i;
    double d;
} u;

程序员可以访问 u.iu.d,但不能同时访问这两个成员。由于 u.iu.d 占用相同的内存区域,修改其中一个会修改另一个的值,有时会以不可预测的方式发生。这也是联合体在实践中很少使用的主要原因。

联合体的大小是其最大成员的大小。

枚举(Enumerations)

枚举是人工数据类型,用于表示标签和整数之间的关联。与结构体或联合体不同,枚举并不是由其他数据类型组成的。以下是一个示例声明:

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 中模拟关联数组的一种简化方式。

最后修改: 2025年01月12日 星期日 13:26