代码大全第二版读书笔记 第四部分-语句 十九、一般控制问题

一般控制问题(P431)

1.布尔表达式(P431)

1)用true和false做布尔判断

在布尔表达式中应该用标示符true和false,而不要用0和1等数值。
  • 隐式地比较布尔值与true和false
    if(!printerError){
    	initializePrinter();
    }
    if(printerError){
    	notifyUserOfError();
    }
    if(reportSelected == reportType_First){
    	printReport();
    }
    if(summarySelected){
    	printSummary();
    }
    if(!printerError){
    	cleanupPrinter();
    }

2)简化复杂的表达式

  • 拆分复杂的判断并引入新的布尔变量
  • 把复杂的表达式做成布尔函数
    如果这个判断只用一次,你可能会认为没有必要把它放入一个子程序中。不过,把这个判断放到一个命名良好的函数里能改善可读性,并且能让你清楚地了解代码在做什么,因而这样做很有必要。
  • 用决策表代替复杂的条件
    即表驱动法

3)编写肯定形式的布尔表达式

大多数人在理解一长串否定用语的时候都会觉得困难。
  • 在if语句中,把判断条件从否定形式转换为肯定形式,并且互换if和else子句中的代码。
  • 用狄摩根定理简化否定的布尔判断
    if( !displayOK || !printerOK)...
    //等价于
    if( !(displayOK && printerOK))...

4)用括号使布尔表达式更清晰

//括号过少的表达式
if( a < b == c == d)...

5)理解布尔表达式是如何求值的

在求布尔表达式值的时候,很多语言会使用一些隐含的控制方式。一些语言的编译器会先计算布尔表达式中的每个项的值,然后再把这些项组合起来求出整个表达式的值。一些语言的编译器采用“短路”或者“惰性”求值,只求出那些必须的部分。当你希望用第一个判断的结果来控制第二个判断是否执行的时候,这一点就显得尤为重要了。

//伪代码示例:易错的判断
while(i < MAX_ELEMENTS and item[i] <> 0)...
如果整个表达式都被求值,你就会在循环的最后一次迭代中遇到一个错误。那时变量i等于maxElements,所以表达式item[i]就等于item[maxElements],而这是一个数组下标越界错误。

//重新安排结构后的正确判断
while( i < MAX_ELEMENTS)
	if( item[ i] <> 0) then
很多语言都提供了相应的功能,在第一时间阻止此类错误的发生。例如,C++和Java采用短路求值:如果and的第一个操作数为假,那么就跳过第二个操作数,因为整个表达式的取值反正一定为假了。

//利用短路求值的判断(不会产生除0错误)
if( (denominator != 0) && ( ( item / denominator) > MIN_VALUE))...
//利用短路求值的判断(可能产生除0错误)
if( ( ( item / denominator) > MIN_VALUE) && (denominator != 0))...
在Java中还有一种“逻辑”运算符,无论整个表达式的结果能否通过部分项的真假判定而无需完全求值,所有的项都要经过完整的求值。区别如下:

//利用短路求值的判断(可能产生除0错误)
if( (denominator != 0) & ( ( item / denominator) > MIN_VALUE))...
不同的语言所用的求值方法是不同的,而语言的实现者们也倾向于随意地对待表达式的求值,所以请查阅你所用语言特定版本的用户手册,以了解你的语言是如何求值的。

6)按照数轴的顺序编写数值表达式

应该很好地组织数值判断,使其顺序与数轴上的点排列顺序相符。
//如果i在中间范围
MIN_ELEMENTS <= i and i <= MAX_ELEMENTS;
//如果i在两边范围
i < MIN_ELEMENTS or MAX_ELEMENTS < i;

7)与0比较的指导原则

  • 隐式地比较逻辑变量
    while( !done)...
  • 把数和0相比较
    如果balance是一个数值类型
    应该写成
    while( balance != 0)
    而不要写成
    while( balance)
  • 在C中显式地比较字符和零终止符 ('\0')
    while( *charPtr != '\0')
    而不是
    while( *charPtr)
  • 把指针与NULL相比较
    while( bufferPtr != NULL)...
    而不是
    while( bufferPtr)

8)布尔表达式的常见问题

  • 在C家族语言中,应该把常量放在比较的左端
    //将常量放在等号右侧——编译器可能不会捕获这个错误
    if( i = MIN_ELEMENTS)...
  • 在C++中,可以考虑创建预处理宏来替换&&,||和==(不得已的时候)
  • 在Java中,应该理解a==b和a.equals(b)之间的差异

2.复合语句(语句块)(P443)

  • 把括号对一起写出
  • 用括号来把条件表达清楚

3.空语句(P444)

C++中可以写空语句,即一条仅含有分号的语句,如下所示:
//传统的空语句
while(recordArray.Read( index++) != recordArray.EmptyRecord() )
	;
  • 小心使用空语句
  • 为空语句创建一个DoNothing()预处理宏 或者内联函数
  • 考虑如果换用一个非空的循环体,是否会让代码更清晰

4.驯服危险的深层嵌套(P445)

避免深层嵌套并不太难。如果你写出了深层的嵌套,那么可以重新设计if和else子句中执行的判断,或者把代码重构为更简单的子程序。
  • 通过重复检测条件中某一部分来简化嵌套的if语句
  • 用break快来简化嵌套if
  • 把嵌套if转换成一组if-then-else语句
  • 把嵌套if转换成case语句
  • 把深层嵌套的代码抽取出来放进单独的子程序
  • 使用一种更面向对象的方法
  • 重新设计深层嵌套的代码

5.编程基础:结构化编程(P454)

结构化编程的核心思想很简单,那就是一个应用程序应该只采用一些单入单出的控制结构。

1)结构化编程的三个组成部分

  • 顺序
  • 选择
    if-else和switch等
  • 迭代
    while和for等

6.控制结构与复杂度(P456)

就直觉而言,程序的复杂度看来在很大程度上决定了理解程序所需要花费的精力。

1)复杂度的重要性

“有能力的程序员会充分地认识到自己的大脑容量是多么地有限;所以,他会非常谦卑地处理编程任务”

2)降低复杂度的一般原则

最著名的是Tom McCabe的方法。该方法通过计算子程序中“决策点”的数量来衡量复杂度

a.如何度量复杂度

  1. 从1开始,一直往下通过程序
  2. 一旦遇到以下关键字,或者其同类的词,就加1:
    if、while、repeat、for、and、or
  3. 给case语句中的每一种情况都加1

b.如何处理复杂度的度量结果

0-5子程序可能还不错
6-10得想办法简化子程序了
10+把子程序的某一部分拆分成另一个子程序并调用它

10个决策点的上限并不是绝对的。应该把决策点的数量当做一个警示,该警示说明某个子程序可能需要重新设计了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值