第10章 结构和联合
10.1 结构声明
Struct {
int a;
Char b;
Float c;
}x;
Struct {
int a;
Char b;
Float c;
}y[20],*z;
警告:这两个声明被编译器当成两个截然不同的类型,即使它们的成员列表完全相同。因此,y和z的类型和x的类型不同,所以下面的语句:z=&x 是非法的
如果想在多个文件中使用同一种类型的结构,应该把标签声明或typedef 声明放在一个头文件中,当源文件需要这个声明时可以使用include指令把那个头文件包含进来
一个结构的成员的名字可以和其他结构的成员的名字相同
结构的初始化
结构的初始化和数组的初始化很相似
如果初始列表的值不够,剩余的结构成员将使用缺省值进行初始化
10.3结构的存储分配
有时,我们有足够的理由,决定不对结构的成员进行重排以减少因对齐造成的空间损失。例如,我们想把相关的结构成员存储在一起,提高程序的可读性和可维护性。但是,如果不存在这样的理由,结构成员应该按照它们的边界需要进行重排
10.4作为函数参数的结构
传递给函数的是一个指向结构的指针。结构越大,把指向它的指针传递给函数的效率就越高
向函数传递指针的缺陷在于函数现在可以对调用程序的结构变量进行修改,如果我们不希望如此,可以在函数中使用const关键字来防止这类修改
对于绝大多数结构,传递指针显然效率更高
10.6 联合体
联合的长度总是足以容纳它最大的成员
如果这些成员的长度相差悬殊,当存储长度较短的成员时,浪费的空间是相当可观的。在这种情况下,更好的方法是在联合中存储指向不同成员的指针而不是直接存储成员本身
联合变量可以被初始化,但初始值必须是联合第一个成员的类型,而且它必须位于一对花括号里面,例如:
Union
{
int a;
float b;
char c[5];
}x={5}
把x.a初始化为5
我们不能把这个变量初始化为一个浮点型或字符型。如果给出的初始值是其他任何类型,它就会转换为一个整数并赋值给x.a
10.7 总结
可以使用结构标签在不同的声明中创建同样类型的结构变量,typedef也可以用于实现这个目标
在不同的结构中出现同样的成员名是不会引起冲突的
sizeof返回的值包含了结构浪费的内存空间
第11章 动态分配内存
11.2 malloc和free
malloc分配的是一块连续的内存.同时,malloc实际分配的内存有可能比请求的稍微多一些
如果操作系统无法向malloc提供更多的内存,malloc就返回一个NUL指针,因此,对每个从malloc返回的指针都进行检查,确保它不是NUL是非常重要的
向free传递一个NUL参数不会产生任何效果
11.3 realloc和calloc
malloc和calloc的主要区别是后者在返回指向内存的指针之前把它初始化为0
calloc的参数是你需要分配的元素个数和每个元素长度
realloc用于修改一个原先已经分配的内存块的大小,使用这个函数,可以使原先的内存扩大或缩小
如果原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并且把原先那块的内容复制到新的块上。因此,在使用realloc之后,就不能再使用指向旧内存的指针,而是应该改用realloc返回的新指针
如果realloc函数的第一个参数是NUL,那么它的行为就和malloc一样
11.5 常见的动态内存错误
释放一块内存的一部分是不允许的。动态分配的内存必须整块一起释放。但是,realloc可以缩小一块动态分配的内存,有效释放它尾部的部分内存
不要访问已经被free函数释放了的内存
内存泄漏
当动态分配的内存不再需要使用时,它应该被释放,这样它以后可以被重新分配使用。分配内存但在使用完毕后不释放将引起内存泄漏
11.7总结
如果一个指针不是从早先的malloc,realloc,calloc函数返回的,它是不能作为参数传递给free函数的
动态分配内存有助于消除程序内部存在的限制
使用sizeof计算数据类型的长度,提高程序的可移植性
第12章 使用结构和指针
12.4总结
遍历链表是根据指针执行的,所以节点的物理排列无关紧要,单链表只能以一个方向进行遍历
语句提炼是一种简化程序的技巧,其方法是消除程序中冗余的语句
如果不同的语句事实上执行相同的功能,可以把它们写成相同的样子,然后再使用语句提炼简化程序
12.6 编程提示的总结
消除特殊情况使代码更易于维护
通过提炼语句消除if语句中的重复语句
不要仅仅根据代码的大小评价它的质量