一、结构体的基本概念
-
什么是结构体?
结构体(struct
)是C语言中一种用户自定义的数据类型,用于将多个不同类型的数据组合成一个逻辑整体。
例如:学生信息可以包含name
(字符串)、age
(整型)、score
(浮点型)等不同数据。 -
为什么需要结构体?
-
将相关数据聚合,提高代码可读性和维护性。
-
便于传递复杂数据(如函数参数或返回值)。
-
模拟面向对象编程中的“对象”概念。
-
结构体是一些值的集合,这些值被称为成员变量,结构体的每个成员可以是不同类型的变量;如:数组,指针,甚至是其他结构体。
二、结构体的声明与定义
1.声明结构体类型
struct Student {
char name[20]; // 姓名
int age; // 年龄
float score; // 成绩
}; // 注意分号不能省略
2.定义结构体变量
方式1:先声明类型,再定义变量
struct Student stu1; // stu1是结构体变量
方式2:声明类型时直接定义变量
struct Student {
// 成员...
} stu1, stu2; // 同时定义stu1和stu2
3.初始化结构体
// 按成员顺序初始化
struct Student stu1 = {"Alice", 18, 95.5};
// C99支持指定成员初始化(顺序无关)
struct Student stu2 = {
.age = 20,
.name = "Bob",
.score = 88.0
};
三、结构体成员的访问
1.使用点运算符(.)访问成员
struct Student stu1;
strcpy(stu1.name, "Tom"); // 字符串赋值需用strcpy
stu1.age = 19;
stu1.score = 92.5;
2.使用指针访问成员(箭头运算符 ->
)
struct Student *p = &stu1;
printf("Name: %s\n", p->name); // 等价于(*p).name
四、结构体的内存对齐
1.对齐原则
-
结构体成员的地址必须是其自身大小的整数倍。
-
结构体总大小是最大成员大小的整数倍。
struct Example {
char a; // 1字节(偏移0)
int b; // 4字节(偏移4,因为1不是4的倍数)
double c; // 8字节(偏移8)
}; // 总大小:1 + 3(填充) + 4 + 8 = 16字节
2.手动控制对齐
使用预处理指令:
#pragma pack(1) // 按1字节对齐(取消对齐)
struct Example {
// 成员...
};
#pragma pack() // 恢复默认对齐
五.结构体的嵌套
1.结构体包含其他结构体
struct Date {
int year;
int month;
int day;
};
struct Student {
char name[20];
struct Date birthday; // 嵌套结构体
};
2.自引用结构体(用于链表、树等)
struct Node {
int data;
struct Node *next; // 指向自身类型的指针
};
六.结构体与函数
1.结构体作为函数参数
void printStudent(struct Student stu) {
printf("Name: %s\n", stu.name);
}
// 注意:传递结构体会产生拷贝,大结构体建议用指针
2.结构体作为返回值
struct Student createStudent() {
struct Student s = {"Lucy", 20, 90};
return s;
}
3. 结构体指针作为参数
void modifyStudent(struct Student *p) {
p->age += 1; // 直接修改原结构体
}
七.结构体的不同用法
1.匿名的结构体类型
在声明结构体的时候可以使用不完全声明。匿名的结构体类型,如果没有对结构体类型重命名的话,基本只能使用一次。
struct
{
int a;
char b;
}x;
2.typedef简化结构体类型名
typedef struct Student {
// 成员...
} Student; // 直接使用Student代替struct Student
Student stu3; // 无需写struct关键字
3.柔性数组成员(C99)
结构体最后一个成员可以是未知大小的数组
struct FlexArray {
int length;
int data[]; // 柔性数组
};
注意事项
-
结构体赋值是深拷贝(逐成员复制)。
-
结构体大小需用
sizeof
获取,而非手动相加。 -
结构体中的数组成员(如
char name[20]
)不能直接赋值,需用strcpy
。 -
避免结构体包含过大的数据(如大数组),以免栈溢出。