在 C 语言中,构造数据类型(也叫复合数据类型)包括结构体(struct
)、共用体(union
)和枚举类型(enum
)。这些类型允许用户根据需求创建复杂的数据结构。下面是对每种类型的详细解析以及需要注意的细节和常见的陷阱。
struct
)结构体是 C 语言中最常用的复合数据类型,它允许将不同类型的数据(例如整数、字符数组等)组合在一起形成一个新类型。
struct Student { char name[50]; // 字符数组 int age; // 整数 float score; // 浮点数 };
struct Student s1; // 定义一个结构体变量 s1 strcpy(s1.name, "Alice"); s1.age = 20; s1.score = 88.5;
a
和 b
的总大小是 5 字节,但由于对齐要求,结构体的实际大小可能会是 8 字节(或者更大),具体取决于平台。结构体传递方式:结构体作为函数参数时,默认是按值传递的,意味着会创建结构体的副本。如果结构体比较大,传递的开销较大。可以使用指针来避免这个问题:
void printStudent(struct Student *s) { printf("%s\n", s->name); }
初始化:结构体可以在定义时进行初始化:
struct Student s1 = {"Alice", 20, 88.5};
union
)共用体是一种特殊的结构体,允许多个成员共享同一段内存。所有成员共享相同的内存位置,但同一时间只能存储一个成员的值。
union Data { int i; float f; char str[20]; };
union Data data;
data.i = 10; // 存储整数
data.f = 3.14; // 存储浮点数(会覆盖 i 的值)
strcpy(data.str, "Hello"); // 存储字符串(会覆盖 f 的值)
data
中存储了一个 int
值,接着存储一个 float
,之前存储的 int
值会被覆盖。enum
)枚举是用来定义一组命名的整数常量。通过枚举,你可以给常量赋予有意义的名字,从而使代码更加可读和易于理解。
enum Weekday { Monday = 1, // 可以显式指定值 Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
enum Weekday today; today = Wednesday; // 枚举类型变量赋值
Monday
默认是 0,Tuesday
是 1,依此类推,除非显式地指定其他值。int
),因此你不能直接确定其内存占用,除非使用 sizeof
来确认。typedef
)typedef
关键字允许为已存在的类型创建别名。这对于构造清晰、易读的代码特别有用。
typedef struct Student { char name[50]; int age; float score; } Student; // 创建 Student 类型别名
Student s1; // 现在可以直接使用 Student 来定义变量
typedef
并不创建新的数据类型,它只是给现有的数据类型起一个新的名字。结构体指针在 C 中非常常见,尤其是在涉及动态内存分配、传递大型结构体时。结构体指针可以通过 ->
操作符来访问结构体成员。
struct Student { char name[50]; int age; }; struct Student *p = malloc(sizeof(struct Student)); strcpy(p->name, "Tom"); p->age = 21; free(p);
C 语言不提供自动垃圾回收,结构体和其他数据类型需要手动管理内存。特别是使用动态分配内存时,必须确保在不再使用时释放内存:
malloc()
或 calloc()
分配内存。free()
释放内存。struct Student *s = malloc(sizeof(struct Student)); if (s != NULL) { strcpy(s->name, "John"); s->age = 22; free(s); // 释放内存 }
构造数据类型是 C 语言中非常强大的功能,它允许你根据具体需求设计和使用复杂的数据结构。使用时要特别注意以下几个问题: