前面使用的if语句在指定的条件为true时执行一个语句。接着,程序按顺序执行下一个语句。当然,有时我们希望只有在条件为false时才执行某个语句或语句块。为此,就要扩展if语句,允许在条件为true时执行一组动作,在条件为false时执行另一组动作。之后,程序按顺序执行下一个语句。这描述为if-else语句。
if-else组合提供了两个选项供选择,其一般逻辑如图4-2所示。

图4-2 if-else语句的逻辑
图4-2中的流程图指出了语句的执行顺序取决于if条件为true还是false。如图所示,在可以使用语句的地方,总是可以使用一个语句块来代替。这就允许为if-else语句的每个选项执行任意多条语句。
仍然使用char类型的变量,编写一个if-else语句,报告存储在变量letter中的字符是否为字母或数字。
if(std::isalnum(letter))
std::cout << "It is a letter or a digit." << std::endl;
else
std::cout << "It is neither a letter nor a digit." << std::endl;
这个程序使用了<cctype>头文件中的函数isalnum()。如果变量letter包含字母或数字,函数isalnum()就返回一个正整数。因为if语句把这个看作是true,所以显示第一个消息。如果变量letter包含的不是字母或数字,函数isalnum()就返回0。对于if来说,这会自动转换为false,执行else之后的输出语句。
程序示例4.5—— 扩展if语句
下面用一个例子来演示if-else语句,这次测试的是数值:
//Program 4.5 Using the if-else
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
long number=0; //Store input here
cout << "Enter an integer less than 2 billion: ";
cin >> number ;
cout << endl;
if (number % 2L ==0) //Test remainder after division by 2
cout << " \n Your number is even." //Here if remainder is 0
<< endl;
else
cout << " \n Your number is odd." //Here if remainder is 1
<< endl;
return 0;
}
这个程序的输出如下所示:
Enter an integer less than 2 billion: 123456
Your number is even.
例子的说明
在把输入的值读入number之后,就在if条件中测试该数除以2的余数(使用第2章介绍的取余运算符%),检查它是否为0。整数除以2后的余数只能是1或0,程序中的代码进行了注释。如果余数等于0,if条件就是true,执行if之后的语句。如果余数等于1,则if条件为false,就执行else关键字后面的语句。在输出结果后,执行return语句,结束程序。
注释:
else关键字的后面没有分号,这与语句中的if一样。这里也采用了缩进格式,作为各个语句之间关系的可视化指示符。可以清楚地看出哪个语句在得到true时执行,哪个语句在得到false时执行。在程序中,应总是缩进语句,显示它们的逻辑结构。
在这个例子中,演示了编写if条件的另一种方式。在转换为bool类型时,任何非0值都是true,而0值转换为false。所以,可以把模式化操作的结果用作条件,而不需要比较它和0值。这样,if-else语句就变成:
if(number % 2L) //Test remainder after division by 2
cout << " Your number is odd." //Here if remainder is 1
<< endl;
else
cout << " Your number is even." //Here if remainder is 0
<< endl;
if和else子句需要调换,因为如果number的值是偶数,则(number % 2L == 0)就返回true,而(number % 2L)会转换为false。初看起来这似乎有点让人迷惑,但这个条件的第一个版本如下:
“余数为0是true吗?”
由于1会转换为true,因此,该条件的第二个版本应如下:
“余数是1吗?”
嵌套的if-else语句
前面介绍了如何在if语句中嵌套if语句。显然,也可以在if语句中嵌套if-else语句,在if-else语句中嵌套if语句,在if-else语句中嵌套其他if-else语句,这样就提供了极大的灵活性(同时也很容易出现混淆),下面就举几个例子。先看第一种情况,在if语句中嵌套if-else语句:
if(coffee=='y')
if(donuts=='y')
std::cout << " We have coffee and donuts ."
<< std::endl;
else
std::cout << " We have coffee, but not donuts."
<< std::endl;
其中,coffee和donuts是char类型的变量,其值分别是'y'和'n'。由于对donuts的测试仅在coffee测试的结果为true时才进行,因此在每种情况下,消息都会反映正确的情形。else属于donuts测试中的if语句。这很容易引起混淆。
如果编写这些代码时,缩进格式有错误,就会推导出错误的结论:
if(coffee=='y')
if(donuts=='y')
std::cout << std::endl
<< "We have coffee and donuts .";
else //This else is indented incorrectly
std::cout << " We have no coffee…" //Wrong!
<< std::endl;
代码的缩进让人错误地认为if语句嵌套在if-else语句中,实际上并非如此。第一个消息是正确的,但执行else后的结果就是错误的。这个语句仅在对coffee的测试为true时才执行,因为else属于donuts的测试,不属于coffee的测试。这个错误很容易看出,但if结构越大就越复杂,就越需要弄清楚哪个if拥有哪个else。
注意:
else总是属于前面最接近的那个if(只要另一个else还不属于这个if)。这种混淆称为else悬挂问题。
在程序中,只要一组if-else语句看起来有些复杂,就可以应用这个规则,对该组语句排序。在编写程序时,应总是使用花括号,使代码更清晰。在这样简单的情形中不需要使用花括号,但可以把上一个例子改写为:
if(coffee=='y') {
if(donuts=='y')
std::cout << "We have coffee and donuts ."
<< std::endl;
else
std::cout << " We have coffee, but not donuts."
<< std::endl;
}
现在代码非常清晰了,else肯定属于测试donuts的if语句。
理解嵌套的if语句
知道了规则后,理解if语句嵌套在if-else语句的情形就比较容易了:
if(coffee=='y') {
if(donuts=='y')
std::cout << " We have coffee and donuts ."
<< std::endl;
}
else if(tea=='y')
std::cout << " We have no coffee, but we have tea"
<< std::endl;
提示:
注意这里的代码格式。一个if语句嵌套在else的下面,可以把else和if写在一行上,本书后面的例子就是这样编写的。
这次,花括号是必不可少的。如果省略了花括号,else就属于测试donuts的if语句了。在这种情况下,很容易忘记加上花括号,生成一个很难找出的错误。有这种错误的程序也会编译,因为代码是完全正确的。有时甚至结果也是正确的,但它没有表达出我们真正的意图。
如果在这个例子中删除花括号,则只要coffee和donuts都等于'y',就不会执行if(tea == 'y')检查,从而得到正确的结果。
最后,看看一个if-else语句嵌套在另一个if-else语句中的情况。即使只有一层嵌套,也可能非常混乱。最好对coffee和donuts进行彻底的分析,再开始使用这种嵌套:
if(coffee=='y')
if(donuts=='y')
std::cout<< " We have coffee and donuts ."
<< std::endl;
else
std::cout<< " We have coffee, but not donuts."
<< std::endl;
else if(tea=='y')
std::cout<< " We have no coffee, but we have tea, and maybe donuts…."
<< std::endl;
else
std::cout<< "No tea or coffee, but maybe donuts…"
<< std::endl;
即使采用了正确的缩进格式,这里的逻辑看起来也不是很明显。不需要使用花括号,因为前面的规则已校验,但如果加上花括号,看起来会更清楚一些:
if(coffee=='y') {
if(donuts=='y')
std::cout<< " We have coffee and donuts ."
<< std::endl;
else
std::cout << " We have coffee, but not donuts"
<< std::endl;
}
else
{
if(tea=='y')
std::cout<< " We have no coffee, but we have tea, and maybe donuts…."
<< std::endl;
else
std::cout<< " No tea or coffee, but maybe donuts…"
<< std::endl;
}
在程序中处理这种逻辑还有更好的方式。如果把足够多的嵌套if语句放在一起,肯定会出错。下一节将简化这个过程。





