3.1.条件语句
先来看以下两个条件if语句:
if语句在括号内的比较表达式为真的情况下执行,需要执行超过一个语句的时候,像第二种写法那样使用语句块。有一种习惯用法,不管是否需要语句块,都采用第二种写法。这样做的好处是,在代码修改过程中,可能需要增减语句,那样的话就不需要临时增加花括号。C语言编译器对花括号的处理不影响编译结果,也不影响运行效率。
就像下面的例子,可以比较容易地在语句块里面增加语句。
当inum1或者inum2为负数的时候,程序提前退出(非正常流程)。调整一下逻辑顺序,进一步完善“cex004.c”文件中的代码并保存。
注意到第8~11行代码与上面写法等效,因为两个条件只要有一个满足就提前退出,所以应该是逻辑的或关系。第12~17行是If-Else语句,else语句是条件不满足的情况下执行,注意到这种语句可以嵌套,并且可以嵌套很多层。
3.2.选择语句
If-Else语句在多层嵌套的时候,代码不够简洁明了,因此我们用选择语句switch对这个程序进行了再次调整。
补全完整的代码,这样就形成了一个实现了四则运算的小程序。
下面编译运行这个程序,看一下运行结果。第一次输入加法参数,得到预期的结果;第二次在除法运算中故意输入除数0,程序提示非正常退出。
这种选择switch语句允许多个入口,case值相等的时候程序就进入后面的语句。这里有两点需要注意,case值只能做整型相等判断,如果case之后没有break语句,程序直接进入下一个case语句,将共用后面的代码,也可能出现共用多个case语句的情况。因此,如果不想出现这种情况,须要注意哪些地方不能漏掉break语句,否则虽然出现没有语法错误,但却存在逻辑错误。如果没有一个case被匹配到,或者之前的case语句没有被break语句拦截,程序就会进入default入口。
下面举几个例子,牢记它们,在实践中肯定能用得上。
图中的“+”入口没有break,于是程序进入到“-”入口,这样计算结果就错误了。
图中的“/”入口没有break,于是程序进入到default入口,程序错误地提前退出。
图中的default入口,可以对ch值做范围判断,在实践中经常会遇到类似的需求,可以参照这样的代码写法。
要经常留意类似上面这种逻辑表达式的写法,对编程水平的提高很有好处,下面专门针对表达式和条件语句做一个小结。
3.3.小结
在表达式中括号的使用,可以有效地避免逻辑上的错误,这是一种良好的编码习惯,也从很大程度上提高了代码的可读性。
对比以下几种写法有哪些优缺点。
与前面的那段代码相比,第26行由于缺少括号,逻辑变得不清晰了,并且也得不到预期的结果。
第26行if语句的表达式是一个逗号表达式,代码意图不明确,可读性不好。另外,逗号表达式也没什么应用场景,除了可以将几个逗号表达式罗列在一起以外,实在看不出来它有什么用,所以实践中要尽量避免使用。
第27行同样是意图不明确,有一种可能是做相等比较时候漏了一个等号。C语言中一个等号是赋值操作符,两个等号才是关系操作符。因此,在某些团队硬性规定,在关系表达式中常量写到前面,比如原本应该写“result == 0”表达式的,改写成“0 == result”。这样即使是漏写了一个等号,变成“0 = result”表达式,但由于这种表达式是非法的,所以编译器可以帮我们把这个语法错误检查出来。而对于漏写等号的“result = 0”,由于没有语法错误,编译是可以通过的,从而遗留了一个不易察觉的逻辑错误。
对此我有不同看法,因为不是所有的关系表达式都包含常量,经常也对两个变量进行比较,那么该如何处理呢?并且在if语句里面写赋值表达式,虽然没有语法错误,但编译器也并不是对它一点反应都没有的。这种语法上合法,但是存在潜在的逻辑隐患,编译器经常会提出警告。如果你想成为一个优秀的程序员,就不应该对编译器的警告视若无睹。在现实中有些项目即使是出现铺天盖地的警告,竟然长年累月都没有人去处理,以至于某一天发现有个严重BUG,才发现原来编译器早就提前预告了隐患的存在,只是我们疏忽大意了。所以平常应该培养一个良好的习惯,尽量写出高质量的代码,并且充分利用编译器或者其它工具的能力,去避免一些看起来不起眼的问题,这是一个优秀程序员应该具备的品质。
此外,如果确实是需要在赋值语句之后,再做进一步的处理,最好能够将这些语句分开来写。第30、31行就是这样的例子,可能你很对操作符的优先级次序很有把握,但也可能没有,也有可能读你代码的人没有把握,这些都是干扰因素。代码应该在逻辑正确的前提下保持清晰易懂的风格。
第32行是一个典型的反面教材,如果你在公司里面这样写,很可能会被炒鱿鱼。首先,不同编译器对这样的代码可能会有偏差,其次这样的代码究竟意味着什么,你最好不要让人家来猜测你的意图。但是,有一个很悲哀的事实是,学校里的老师很喜欢出这种题目来考学生,这就是在误人子弟,但这也没有办法,毕竟他们掌握着你的学分。
K&R经典书籍《The C
Programming Language》里面提到了两种if语句的对比,他认为第一种写法在这种情况下更优,因为“valid”表示合法,“!valid”很容易让人想到就是非法。
C语言中逻辑操作符“!”表示否运算,对真做否运算结果为假,否则为真。由于之前C语言没有布尔类型,所以他说的情况确实也有道理。但是如果以后引入布尔类型,对于布尔类型的表达式“valid == false”,其实可读性是很好的。所以,我更倾向于后面的写法,否运算更适合在赋值语句里面,逻辑表达式里面可以不用。下面还是再给个例子吧。
类似上面这样的写法,代码逻辑就相当的清晰了。
C语言中的操作符分为单目操作符、双目操作符与三目操作符。上面的否运算就是单目操作符,它只有一个操作数,再比如之前用的取地址符“&”也是单目操作符。双目操作符更加常见一点,前面的四则运算都是双目操作符。C语言只有一个三目操作符,见下列的条件表达式。
第26、27行和第28行的功能都是找出两个数中较大的哪个数,但是后者写起来更简洁,这就是C语言的优美所在。前面关系表达式的运算结果是一个操作数,连同两个整型变量,总共是三个操作数。