6.1 结构的基本知识
坐标:
// 结构声明
// point 是结构标记, 可选的
struct point {
// 成员
int x;
int y;
};
struct 声明定义了一种数据类型 (所以不是该结构的变量声明).
声明某结构的变量:
struct {...} x, y, z;
结构变量初始化:
struct point maxpt = {320, 200};
引用成员:
结构名.成员
嵌套结构:
struct rect {
struct point pt1;
struct point pt2;
};
// 引用成员
struct rect screen;
screen.pt1.x
6.2 结构与函数
结构的合法操作:
- 作为整体复制和赋值
- 传递参数
- 从函数返回
- 通过 & 取地址
- 访问其成员
结构之间不能比较.
传递结构的3中方法:
- 分别传递各个结构成员
- 传递整个结构
- 传递结构指针
()
是必须的,.
的优先级比*
高
struct point origin, *pp;
pp = &origin;
printf("origin is (%d, %d)\n", (*pp).x, (*pp).y);
// 简写形式
p->结构成员
由优先级带来的复杂度:
.
->
f()
a[]
运算符在所有运算符中优先级较高
6.3 结构数组
struct key {
char *word;
int count;
} keytab[NKEYS];
// 分开
struct key {
char *word;
int count;
};
struct key keytab[NKEYS];
直接初始化:
- 编译器计算数组的大小
- 内部也可以用
{}
分隔
{
{"auto", 0},
...
};
折半查找:
一元运算符 sizeof 可以用来计算对象的长度:
sizeof 对象
sizeof(类型名)
获得 NKEYS 的大小:
条件编译 #if 中不能使用 sizeof.
6.4 指向结构的指针
注意:
- 指针间的运算
mid = (low+high) / 2; // 错误, 指针间的加法运算是非法的, 减法是合法的
mid = low + (high-low) / 2; // 合法
- 数组范围
&tab[-1]; // 非法
&tab[n]; // 非法, 但是 C 语言的定义保证数组末尾之后的第一个元素的指针算术运算可以正确执行
- 结构大小
// 因为对齐, 结构的长度不是各字段长度之和.
// 可能需要 8B, 应该使用 sizeof 获得正确的大小.
struct {
char c;
int i;
};
6.5 自引用结构
使用二叉树存储输入 (更通用的单词统计程序):
结构:
自引用是确定的, 因为指针大小是确定的.
循环引用:
新的统计程序:
- 将 word 添加到 tree 中的过程就是统计的过程
递归调用:
中序遍历:
内存分配函数的问题:
- 如何满足不同机器的对齐要求
- 如何声明函数可以返回不同对象的指针
strdup 函数也使用 malloc() 分配空间:
释放空间使用 free 函数.
6.6 表查找
链表节点定义:
指针数组定义:
hash 函数:
- hashCode
6.7 类型定义 (typedef)
创建自定义类型:
typedef int Length;
Length len, maxlen;
typedef char *String;
String p, lineptr[MAXLINES], alloc(int);
int strcmp(String, String);
p = (String) malloc(100);
函数指针别名:
typedef int (*PFI)(char *, char *);
typedef 的两个重要作用:
- 是程序参数化, 提高程序的可移植性 (各种 short, int, long 的别名)
- 为程序提供更好的说明, 为 struct 定义别名
6.8 联合
一个变量可以合法地保存多种数据类型中任何一种类型的对象.
从字面上感觉像是 Go 中的 interface{}, Java 中的 Object.
union u_tag {
int ival;
float fval;
char *sval;
} u;
访问成员:
联合名.成员
联合指针->成员
类型判断:
书中没写 utype 是怎么来的.
在 struct 中定义 union:
引用 ival:
symtab[i].u.ival
引用 sval 的第一个字符:
*symtab[i].u.sval
symtab[i].u.sval[0]
其他:
- 联合就是一个结构, 所有成员相对于基地址的偏移量都为0
- 联合只能用其第一个成员类型的值进行初始化.
6.9 位字段
常见用法:
- 掩码
C 中提供了直接定义和访问一个字中的位字段的能力:
- 位字段: 是字中相邻位的集合
- 字: 单个存储单元, 大小与具体实现有关
:
后的数字表示字段宽度
引用字段:
- 理解: 就是当成占了指定位数的整数
flags.is_keyword
flags.is_extern = flags.is_static = 1;
if (flags.is_extern == 0 && flags.is_static == 0)
...