结构体(struct)是C语言中一种重要的用户自定义数据类型,它允许将不同的数据类型组合在一起,形成一个逻辑单元。
一、基本概念
1.1 为什么需要结构体
基本数据类型(int\float\char等)只能表示单一类型的数据。当需要表示一个复杂的对象(如学生、图书、点坐标)时,需要将多个不同的数据组织在一起:
1 2 3 4 5 6 7 8 9 10 11
| char name[20]; int age; float score;
struct Student { char name[20]; int age; float score; }
|
1.2 结构体的定义
1 2 3 4 5
| struct 结构体名 { 数据类型 成员名1; 数据类型 成员名2; }
|
示例:
1 2 3 4 5 6 7 8 9 10 11
| struct Point { int x; int y; }
struct Student { char name[20]; int age; float score; char gender; }
|
二、结构体变量的声明与初始化
2.1 三种声明方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct Point { int x; int y; }; struct Point p1, p2;
struct Point { int x; int y; } p1, p2;
struct { int x; int y; } p1, p2;
|
2.2 初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| struct Point p1 = {10, 20};
struct Point p2 = {.y = 20, .x = 10};
struct Point p3 = {10};
struct Student { char name[20]; int age; struct Point location; };
struct Student s = {"Tom", 18, {3, 4}};
|
三、访问结构体成员
3.1 点运算符(.)
用于结构体变量:
1 2 3 4
| struct (point p = {10,20}); printf("&d,%d\n",p.x,p.y); p.x = 30; strcpy(s.name,"jerry");
|
3.2箭头运算符(->)
用于结构体指针:
1 2 3 4 5 6
| struct Point p = {10, 20}; struct Point *ptr = &p;
print("%d\n",(*ptr).x); print("%d\n, ptr->x";
|
四、结构体内存布局
4.1 内存对齐
结构体在内存中并非简单地将成员大相加,编译器会进行内存对齐,以提高访问效率。
1 2 3 4 5 6
| struct A { char C; int i; char d; };
|
对其规则:
- 每个成员的偏移量必须是该成员大小的整数倍(或对齐模数的整数倍)
- 结构体总大小必须是最大成员对齐数的整倍数
4.2 控制对齐
1 2 3 4 5 6 7 8
| #pragma pack(push, 1) struct Packed { char c; int i; char d; }; #pragma pack(pop)
|
五、结构体与指针
5.1 结构体指针
1 2 3 4 5 6 7
| struct Student s = {"Tom", 18, 90.5}; struct Student *p = &s;
printf("%s\n", p->name); printf("%d\n", p->age);
p->age = 19;
|
5.2 作为函数参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void printStudent(struct Student s) { printf("%s\n", s.name); }
void updateAge(struct Student *s, int newAge) { s->age = newAge; }
void printStudent(const struct Student *s) { printf("%s\n", s->name); }
|
六、结构体数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct Student students[3] = { {"Tom", 18, 90.5}, {"Jerry", 19, 85.0}, {"Spike", 20, 78.5} };
for (int i = 0; i < 3; i++) { printf("%s: %.1f\n", students[i].name, students[i].score); }
struct Student *p = students; for (int i = 0; i < 3; i++) { printf("%s\n", (p + i)->name); }
|
七、typedef 与结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| struct Point { int x, y; }; struct Point p1;
typedef struct { int x, y; } Point; Point p1;
typedef struct Node { int data; struct Node *next; } Node;
|
八、自引用结构体(链表)
1 2 3 4 5 6 7 8 9 10 11
| typedef struct Node { int data; struct Node *next; } Node;
Node *head = malloc(sizeof(Node)); head->data = 1; head->next = malloc(sizeof(Node)); head->next->data = 2; head->next->next = NULL;
|
九、位域(Bit Fields)
用于节省内存,精确控制成员占用的位数:
1 2 3 4 5 6
| struct Flags { unsigned int flag1 : 1; unsigned int flag2 : 1; unsigned int value : 6; unsigned int : 0; };
|
用途:硬件寄存器、协议报文、位标志等。
十、结构体的复制与比较