C语言学习指南:从规范编程到专业级开发
上QQ阅读APP看书,第一时间看更新

6.5 多个if()...else...语句

switch()...语句测试的是单个值。我们能不能用另一种办法来做这样的测试呢?可以,即通过if()...else if()...else if()...else...形式的结构来做。如果用这种结构来实现calc()函数,那么该函数的代码就是:

这种写法完全正确,然而其中有好几个地方需要解释:

□第一个if()...以及后面的那些else if()...,分别对应于switch()...语句的每一个case:分支,最后那个else...对应于switch()...语句的default:分支。

□前三个if()...的true分支都是一条简单的语句。

□第四个if()...的true分支虽然包含许多行代码,但这些代码合起来其实是一个完整的if()...else...结构,因此这个结构可以视为一条复杂语句。于是我们可以说,第四个if()...的true分支,跟前三个if()...的true分支一样,都只包含一条语句,只不过这次是一个复杂语句,而不是简单语句。

第四个if()...里面的if()...else...结构跟它外面的那一系列if稍微有点区别,因为这个结构检测的是另一个变量,也就是operand2变量,而不像外面那些if那样检测operator变量。这种if()...else...结构被称作嵌套的(nested)if()...语句。

□外面这个大if结构的最后两个分支都各自包含多条简单的语句[1],为了把这些简单的语句合并起来,我们将其括在了花括号中间。

你可以做个实验,把语句外围的{与}去掉,看看会出现什么问题。

□有人可能认为,对于calc()函数来说,用switch()...语句来实现会更加清晰,因此他们会选用switch()...语句来写这个函数,但另一些人可能不这么认为。

刚才这个例子是把某个变量的值与一系列常量作对比,因此既可以用switch()...语句实现,又可以用if()...else if()...else if()...else...实现。然而有些需求却根本无法用switch()...实现。比方说,有时我们想让程序判断某变量的值是否位于某个取值范围内,并根据判断出来的范围给一个或多个变量赋值。例如下面这个describeTemp()函数就是如此,它需要根据调用方传入的degreesF变量,给出一条与该温度相符的描述信息。这个函数的代码是这样的:

这个函数所接受的degreesF变量是double类型,用来表示有待判断的华氏温度值。函数需要通过一系列if()...else...形式的语句来判断这个温度值处于哪个范围,并据此给出一条与该范围相对应的描述信息,以描述人在这种温度下的感受。像这样的需求就很难用switch()...语句实现。

除了刚才那种写法,我们还可以改用&&逻辑运算符来实现describeTemp()函数:

这个版本的describeTemp()函数用多个if()...结构来判断degreeF变量是否位于某个取值范围。除了第一个与最后一个if之外,其余的if所采用的条件表达式都包含一个上限值与一个下限值,以判断受测变量是否位于这两个限值之间。另外我们还要注意,无论degreesF取什么值,这些if中都只会有一个if跟它匹配,而且必然会有这样的一个if。采用这种写法时,一定要保证这些if能够将受测变量可能取到的值全部覆盖到。这样的判断逻辑称为fall-through逻辑(下沉判断逻辑),这种逻辑会把受测变量按照从上到下的顺序依次代入相应的条件中,以判断该变量的值是否能让其中某个条件成立。大家在下一节还会看到更多的fall-through范例。

完整的程序代码写在temp.c文件中这个程序不仅会定义刚才那样一个函数,而且会用位于各种范围内的受测值来调用这个函数,以验证其功能是否正确。编译并运行该程序,你会看到类似下面这样的输出信息:

现在我们可以回到判断闰年的程序了。我们这次所写的程序会正确地处理整百的年份。请复制早前的leapYear1.c文件,并把副本起名为leapYear2.c,我们将要在副本上修改代码。前面那个版本所写的isLeapYear()函数,有一部分内容依然会得到沿用,但是这次,我们会把整四百的年份,与不是整四百但却是整百的年份分开处理:

我们这次所用的逻辑很适合用连续出现的if()...else...结构实现。现在我们已经能够正确处理整四百的年份与不是整四百但却是整百的年份了。请保存leapYear2.c文件,编译并运行该文件。你会看到下面这样的输出信息。

我们通过一系列if()...else...结构把受测年份转化成一个简单的布尔值。这次我们没有像原来那样,只要一发现判断结果就立刻从函数中返回,而是把判断结果保存到一个名为isLeap的局部变量里面,等到函数即将结束时,再把该变量的值返回给调用方。这样做有时要比在各分支里面直接用return语句返回更好,如果函数比较长,或者其中的逻辑比较复杂,那么这种写法的优势会更加明显。

大家注意看,程序现在已经能够正确判断出2000年是闰年而1900年不是闰年了。

[1] 严格来说,第五个if分支下面只有一条语句,笔者这里把// Remaindering:...注释也算作了一条语句。——译者注