常见的if语句问题
本节阅读量:
本课将研究使用if语句时会遇到的一些常见问题。
嵌套的if语句和悬空的else问题
可以将if语句嵌套在其他if语句中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x >= 0) // 外层if条件
// 这样的嵌套if代码样式,非常差
if (x <= 20) // 内层if语句
std::cout << x << " is between 0 and 20\n";
return 0;
}
|
现在考虑以下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x >= 0) // 外层if条件
// 这样的嵌套if代码样式,非常差
if (x <= 20) // 内层if语句
std::cout << x << " is between 0 and 20\n";
// 这个else语句,属于哪个if条件呢?
else
std::cout << x << " is negative\n";
return 0;
}
|
上面的程序引入了一个潜在的歧义源,称为悬空else问题。上面程序中的else语句与外部还是内部if语句匹配?
答案是,else语句会与同一代码块中最后一个尚未匹配else的if语句配对。因此,在上面的程序中,else会与内部if语句匹配,就像程序是这样编写的一样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x >= 0) // 外层if条件
{
if (x <= 20) // 内层if语句
std::cout << x << " is between 0 and 20\n";
else // 内层if语句对应的else
std::cout << x << " is negative\n";
}
return 0;
}
|
这会导致上述程序产生不符合预期的输出:
1
2
|
Enter a number: 21
21 is negative
|
为了在嵌套if语句时避免这种歧义,最好将内部if语句显式放入代码块中。这样就可以明确else属于哪个if语句:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x >= 0)
{
if (x <= 20)
std::cout << x << " is between 0 and 20\n";
else // 与内层if语句对应
std::cout << x << " is greater than 20\n";
}
else // 与外层else语句对应
std::cout << x << " is negative\n";
return 0;
}
|
代码块内的else语句对应内部if语句,代码块外的else语句对应外部if语句。
展平嵌套if语句
嵌套的if语句通常可以通过重新组织逻辑来展平。嵌套较少的代码更不容易出错。
例如,上述示例可以如下展平:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x < 0)
std::cout << x << " is negative\n";
else if (x <= 20) // x 大于等于0,小于等于20
std::cout << x << " is between 0 and 20\n";
else // x大于20
std::cout << x << " is greater than 20\n";
return 0;
}
|
下面是另一个使用逻辑运算符检查单个if语句中的多个条件的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <iostream>
int main()
{
std::cout << "Enter an integer: ";
int x{};
std::cin >> x;
std::cout << "Enter another integer: ";
int y{};
std::cin >> y;
if (x > 0 && y > 0) // 检查x与y同时大于0
std::cout << "Both numbers are positive\n";
else if (x > 0 || y > 0) // 检查x与y,只有一个大于0
std::cout << "One of the numbers is positive\n";
else
std::cout << "Neither number is positive\n";
return 0;
}
|
空语句(Null statements)
空语句是仅由分号组成的表达式语句:
1
2
|
if (x > 10)
; // 这是一个空语句
|
空语句不执行任何操作。它们通常用于语言要求此处必须有语句,但程序员并不需要执行任何操作的场景。为了提升可读性,空语句通常单独占一行。
在本章后面讨论循环时,我们将看到有意使用空语句的示例。空语句很少会有意与if语句一起使用。然而,新的(或粗心的)程序员可能会不小心写出空语句,从而带来问题。请考虑以下片段:
1
2
|
if (nuclearCodesActivated());
blowUpTheWorld();
|
在上面的片段中,程序员不小心在if语句末尾加了一个分号(这是一个常见错误,因为许多语句都以分号结尾)。这段代码可以正常编译,但执行时等价于这样编写:
1
2
3
|
if (nuclearCodesActivated())
; // 分号,这里是一个空语句
blowUpTheWorld(); // 这一行永远能执行到
|
警告
注意不要用分号“终止”if语句,否则true或false对应的语句将无条件执行(即使它们在块中)。
条件表达式中,运算符== 与 运算符=
在条件表达式中测试相等性时,应该使用operator==,而不是operator=(赋值)。考虑以下程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <iostream>
int main()
{
std::cout << "Enter 0 or 1: ";
int x{};
std::cin >> x;
if (x = 0) // oops, 这里使用赋值,而不是相等性测试
std::cout << "You entered 0\n";
else
std::cout << "You entered 1\n";
return 0;
}
|
该程序可以编译和运行,但会产生错误的结果:
1
2
|
Enter 0 or 1: 0
You entered 1
|
事实上,该程序将始终产生结果1。这是因为x = 0首先将值0赋值给x,然后计算x的值,该值现在为0,这是布尔false。由于条件语句结果总是false,因此else语句总是执行。