* 结构体
结构体:是指使用其他类型组建的数据。
通常情况下,我们希望创建类而非结构体,这样除了能使用结构体可以提供的公用数据外,还能利用类所提供的私密性和功能性。但是,有是直接操纵成块的数据会十分方便,下面列出了一些使用结构体的理由。
# 用结构体来明确数据关系
结构体可以把相关联的一组数据项聚集在一起。
# 用结构体简化对数据块的操作
可以把相关的元素组织到结构体里,然后对该结构体执行操作。对结构体执行操作要比对各个元素执行同样的操作容易的多。这样也会更可靠,并且只需更少的代码。
# 用结构体来简化参数列表
可以用结构体来简化子程序的参数列表(我在实践中经常这样干)。
与单独传递每一个需要的元素相比,可以把相关的元素组织到一个结构体里,然后把它作为一个整体传递进去。
# 用结构体来减少维护
由于你在使用结构体的时候是把相关的数据组织在一起的,因此对结构体的修改只会导致对程序做很小的改动。特别是对那些逻辑与结构体变化没有关联的代码来说,这一点尤为正确。
* 指针
指针的使用时现代编程中最容易出错的领域之一,以至于像Java,C#和VB这些现代编程语言都没有提供指针数据类型。对指针的运用具有其固有的复杂性,正确使用指针要求你对所使用编译器的内存管理机制有很好的理解。
# 怎样理解指针
从概念上讲,每一个指针都包含两个部分:内存中的某处位置,以及如何解释该位置中的内容。
内存中的位置就是一个地址,常用16进制形式表示。32位处理器中的一个地址用一个32位的值表示。指针本身只包含这个地址。为了使用该指针所指向的数据,就必须访问该地址,解释该位置的内存内容。
如何解释内存中某个位置的内容,是由指针的基本类型(base type)决定的。如果某指针指向整数,这就意味着编译器会把该指针所指向的内存位置的数据解释为一个整数。当然,你可以让一个整数指针,一个字符串指针和一个浮点数指针都指向同一个内存位置。但是其中(至多)只有一个指针能正确地解释该位置的内容。
# 使用指针的技巧
正确地使用指针要求程序员采用一种双向策略。第一,要首先避免造成指针错误。其次,在编写代码之后尽快地检测出指针错误来。
下面是一些措施:
& 把指针操作限制在子程序或者类里面
& 同时声明和定义指针
& 在与指针分配相同的作用域中删除指针
& 在使用指针之前检查指针
& 先检查指针所引用的变量在使用它
& 增加明显的冗余
就是某些特定字段重复两次,如果位于冗余字段中的数据不匹配,就可以确定数据已经破坏了。
& 用额外的指针变量来提高代码的清晰度
一定不要节约指针变量,就是不要把同一个变量用于多种用途。
& 简化复杂的指针表达式
复杂的指针表达式是很难读懂的,如果你的代码里有类似于p->q->a->r->s->data这样的语句,考虑一下读者的感受吧!
& 画一个图
用代码解释指针可能会让读者感到困惑,画一个图通常会有所帮助。
& 按照正确的顺序删除链表中的指针
& 分配一片保留的内存后备区域
& 粉碎垃圾数据
& 在删除或者释放指针后把它们设为空值
& 在删除变量之前检查非法指针
& 跟踪指针分配情况
& 编写覆盖子程序,集中实现避免指针问题的策略
& 采用非指针的技术
# C++指针
C++中使用指针的指导原则
& 理解指针和引用之间的区别
引用和指针最重要的区别是:引用必须总是引用一个对象,而指针则可以指向空值。还有,引用所指向的对象在该对象初始化之后不能改变。
& 把指针用于“按引用传递”参数,把const引用用于“按值传递”参数
C++向子程序传递参数的默认方式是按值传递而不是传递引用。对于大对象而言,效率比较低,因此可以使用传递引用的方式来实现。但是,此时希望实现具有“传值”语义,所以用const引用。
& 使用auto_ptr
如果你没有养成使用auto_ptr的习惯,那么就努力吧。
& 灵活运用智能指针
# C指针
& 使用显示指针类型而不是默认类型
C允许对任何类型的变量使用char或者void指针,C语言只关心这类指针有所指向,不会真正去关心它所指向的是什么。然后,如果你使用了显式的指针类型,编译器就会针对不相符的指针类型和不合适的解除引用发出警告。如果你不这样做,它就不发警告。因此,请尽可能地使用显式的指针类型。
采纳这项规则的必然结果是,当你必须进行类型转换的时候要使用显式类型转换。
& 避免强制类型转换
如果需要强制类型转换,那么就是在你的防御式编程的铠甲上挖了个洞,一个需要很多强制类型转换的程序在架构方面可能就存在一些需要修正的问题,如果可能,请重新做设计;否则,就应该尽可能地避免强制类型转换。
& 遵循参数传递的型号规则
在C语言里,只有当你在赋值语句的参数前面加上了星号(*),才能把该参数从子程序中传回去。
& 在内存分配中使用sizeof()确定变量的大小
* 全局数据
# 与全局数据有关的问题
& 无意间修改了全局数据
& 与全局数据有关的奇异的和令人激动的别名问题
& 与全局数据有关的代码重入问题
& 全局数据阻碍代码重用
& 与全局数据有关的非确定的初始化顺序事宜
& 全局数据破坏了模块化和智力上的可管理性
# 使用全局数据的理由
如果遵循使用的原则,那么全局变量在一些场合下也是有用的:
& 保存全局数值
& 模拟具名常量
在支持具名常量的语言中模拟具名常量(如Python, Perl, Awk以及UNIX Shell等脚本语言)
& 模拟枚举类型
可以在不支持枚举的语言中来模拟枚举(如Python语言)
& 简化对及其常用数据的使用
& 消除流浪数据
# 只有在万不得已时才使用全局数据
当你选择使用全局数据之前,请考虑下面的替换方案。
& 首先把每一个变量设置为局部的,仅当需要时才把变量设置为全局的
& 区分全局变量和类变量
# 用访问器子程序来取代全局数据
& 如何使用访问器子程序
% 要求所有的代码通过访问器子程序来存取数据
% 不要把所有的全局数据都扔在一处
% 用锁定来控制对全局变量的访问
% 在你的访问器子程序里构建一个抽象层
% 使得对一项数据的所有访问都发生在同一个抽象层上
# 如何降低使用全局数据的风险
& 创建一种命名规则来突出全局变量
& 为全部的全局变量创建一份注释良好的清单
& 不要用全局变量来存放中间结果
& 不要把所有的数据都放在一个大对象中并到处传递,以说明你没有使用全局变量
要点
# 结构体可以使得程序更简单,更容易理解,以及更容易维护
# 每当你打算使用结构体的时候,考虑采用类是不是会工作得更好
# 指针很容易出错。用访问器子程序或类以及防御式编程实践来保护自己的代码
# 避免用全局变量,不只是因为他们很危险,还是因为你可以用更好的其他方法来取代它们
# 如果你不得不使用全局数据,那么就通过访问器子程序来使用它。访问器子程序能为你带来全局变量所能带来的一切优点,还有一些额外好处。
参考
《代码大全》第二版 第十三章 不常见的数据类型