
3.1 选择结构程序设计
3.1.1 关系表达式与逻辑表达式
在介绍选择语句前,我们首先练习一下关系表达式与逻辑表达式。在第2章中,我们了解到算术运算符的优先级高于关系运算符、关系运算符的优先级高于逻辑与和逻辑或运算符、相同优先级的运算符从左至右进行结合等,那么表达式5>3&&8<4-!0的最终值是多少?其计算过程如图 3.1.1所示。

图3.1.1 5>3&&8<4-!0的计算过程
下面再来看一个判断年份是否为闰年的例子(闰年是能被4整除但不能被100整除,或者既能被4整除又能被400整除的年份)。具体的表达式为year%4==0&&year%100!=0||year%400==0,也可以写成(year%4==0&&year%100!=0)||year%400==0,后者虽然可行,但括号显然是多余的。
3.1.2 if语句
在你打开衣柜拿出最上面的一件衣服时,你会判断这件衣服是不是你想穿的。如果是,那么你就会穿上;如果不是,那么你就会去找其他衣服。在计算机中,我们用if判断语句来实现这样的效果:if判断条件(表达式)为真,就执行某个语句,反之不执行这个语句。当然,也可以if判断条件(表达式)为真,就执行某个语句,反之用else分支执行另一个语句,具体流程如图3.1.2和图3.1.3所示。
下面来看一个判断输入值是否大于0的例子。

图3.1.2 if语句流程1

图3.1.3 if语句流程2
当输入值大于0时,打印“i is bigger than 0”,当输入值小于等于0时,打印“i is not bigger than 0”,具体代码如图3.1.4所示。注意,在这个例子中,if后面不能加分号,因为如果有else分支语句,那么加分号会导致编译不通过;如果没有else分支语句,那么加分号会导致i无论取何值,都会打印“i is bigger than 0”。

图3.1.4 判断输入值是否大于0
if语句和else语句也可以多个同时使用(多分支语句),如图3.1.5所示。但是,无论有多少个if语句或elseif语句,程序都只会执行其中的一个语句。下面是一个关于用电量的例子:用电量越高,电的单价越高,但最终cost只会被赋值一次。同时,if语句也支持多层嵌套,在if语句中又包含一个或多个if语句称为if语句的嵌套,如图3.1.6所示。

图3.1.5 多分支语句

图3.1.6 if语句的嵌套

使用if嵌套语句时,要考虑“悬空的else”问题。例如,在下面的例子中,else子句从属于哪个if语句?

和其他绝大多数语言一样,C语言中的else子句从属于最靠近它的不完整的if语句。上例中的else子句从属于第二个if语句,如果想让它从属于第一个if语句,那么可以用一个花括号把第二个if语句包含在一个单独的代码块内,如下所示。

在if语句中的语句列表前后加上花括号,可以防止不小心加了一句代码后,使实际未被包含的语句被包含在某个if语句中的错误。
3.1.3 switch语句
判断的一个变量可以等于几个值或几十个值时,使用if和elseif语句会导致elseif分支非常多,这时可以考虑使用switch语句,switch语句的语法格式如下:

下面来看一个使用switch语句的例子。如例3.1.1所示,输入一个年份和月份,然后打印对应月份的天数,如输入一个闰年和2月,则输出为29天。具体代码如下所示,对应的电子附件项目名称为“switch月份1”,读者会发现,switch语句中case后面的常量表达式的值不是按照1到12的顺序排列的,这里要说明的是,switch语句匹配并不需要常量表达式的值有序排列,输入值等于哪个常量表达式的值,就执行其后的语句,每条语句后需要加上break语句,代表匹配成功一个常量表达式时就不再匹配并跳出switch语句。
【例3.1.1】switch语句的使用。

如果一个case语句后面没有break语句,那么程序会继续匹配下面的case常量表达式。例 3.1.2中的代码是对例3.1.1中代码的优化,对应的电子附件项目名称为“switch月份2”。例 3.1.2中的代码执行效果和上面的代码执行效果一致,原理是只要匹配到1、3、5、7、8、10、12中的任何一个,就不再拿mon与case后的常量表达式的值进行比较,而执行语句printf("mon=%d is 31days\n",mon),完毕后执行break语句跳出switch语句。switch语句最后加入default的目的是,在所有case后的常量表达式的值都未匹配时,打印输出错误标志或者一些提醒,以便让程序员快速掌握代码的执行情况。
【例3.1.2】日期实例改进。
