第6章 结构
1. 结构体基础
1.1 结构体的定义
- 使用
struct
关键字定义复合数据类型:struct point { int x; int y; };
- 结构体可以包含不同类型的成员(
int
,float
,char
等)。 - 结构体变量声明方式:
struct point pt; // 声明一个point结构体变量pt
1.2 结构体成员的访问
- 使用
.
运算符访问成员:pt.x = 10; pt.y = 20;
- 结构体可以嵌套(成员可以是另一个结构体)。
重点难点
- 结构体定义不分配内存,只有声明变量时才分配。
- 结构体不能直接比较(如
pt1 == pt2
是错误的),必须逐成员比较。
2. 结构体操作
2.1 结构体赋值
- 结构体可以整体赋值(按值拷贝):
struct point p1 = {1, 2}; struct point p2 = p1; // p2是p1的副本
2.2 结构体数组
- 可以定义结构体数组:
struct point points[10]; points[0].x = 100;
2.3 结构体作为函数参数
- 可以传值(拷贝整个结构体):
void printPoint(struct point p) { printf("%d, %d", p.x, p.y); }
- 也可以传指针(更高效):
void printPoint(struct point *p) { printf("%d, %d", p->x, p->y); }
重点难点
- 传值 vs 传指针:
- 传值:安全但效率低(大结构体拷贝开销大)。
- 传指针:高效但可能修改原数据(可加
const
防止修改)。
3. 结构体指针
3.1 指向结构体的指针
- 声明方式:
struct point *pp; // 指向point结构体的指针
- 使用
->
访问成员:pp = &pt; printf("%d", pp->x); // 等价于 (*pp).x
3.2 动态内存分配
- 结构体指针常用于动态数据结构(如链表):
struct node *np = (struct node *)malloc(sizeof(struct node));
重点难点
- 指针访问 vs 直接访问:
(*pp).x
和pp->x
是等价的,但->
更简洁。
- 内存管理:
- 动态分配的结构体必须手动释放(
free
),否则内存泄漏。
- 动态分配的结构体必须手动释放(
4. 类型定义(typedef)
4.1 typedef 简化结构体类型
- 使用
typedef
定义新类型名:typedef struct { int x; int y; } Point; // 现在可以直接用 Point 代替 struct point
- 使用方法:
Point p = {1, 2};
重点难点
typedef
只是别名,不创建新类型,编译时仍视为原类型。
5. 联合(union)
5.1 联合的定义
- 联合(
union
)的所有成员共享同一块内存:union data { int i; float f; char c; };
- 同一时间只能存储一个成员的值(修改一个会影响其他)。
5.2 联合的用途
- 节省内存(如存储不同类型但不同时使用的数据)。
- 实现变体数据类型(如解析网络协议数据)。
重点难点
- 联合的大小:由最大成员决定(如
union data
大小是float
的大小)。 - 类型安全:读取错误的成员会导致未定义行为(如存
int
读float
)。
6. 位字段(Bit Fields)
6.1 位字段的定义
- 允许按位定义结构体成员:
struct { unsigned int is_keyword : 1; // 1位 unsigned int is_extern : 1; unsigned int is_static : 1; } flags;
6.2 位字段的用途
- 节省内存(如标志位存储)。
- 直接操作硬件寄存器(如嵌入式开发)。
重点难点
- 可移植性问题:
- 位字段的存储方式(从左到右还是从右到左)由编译器决定。
- 位字段不能取地址(如
&flags.is_keyword
是错误的)。
7. 应用实例
7.1 单词计数程序
- 使用结构体存储单词及其出现次数:
struct key { char *word; int count; } keytab[NKEYS];
7.2 链表实现
- 动态结构体指针构建链表:
struct node { int data; struct node *next; };
重点难点
- 链表操作:
- 插入、删除节点时要注意指针的正确维护,否则会导致内存错误。
8. 总结
8.1 重点回顾
- 结构体:用于组织复杂数据,支持
.
和->
访问。 - 结构体指针:提高效率,用于动态数据结构。
- typedef:简化类型名,提高代码可读性。
- 联合:共享内存,节省空间,但需谨慎使用。
- 位字段:精确控制内存,但可移植性差。
8.2 难点总结
- 结构体传参:大结构体应传指针而非值。
- 动态内存管理:
malloc
和free
必须配对使用。 - 位字段的可移植性:不同编译器可能有不同实现。
本章是C语言高级数据组织的核心内容,掌握结构体和指针的使用是后续学习数据结构(链表、树、图)的基础。