8-3 常见的if语句问题
本课是第8.2课——if语句与代码块的延续。在本课中,我们将探讨使用if语句时常见的一些问题。
嵌套的if语句与悬空else问题
可以在其他if语句内部嵌套if语句:
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x >= 0) // outer if statement
// it is bad coding style to nest if statements this way
if (x <= 20) // inner if statement
std::cout << x << " is between 0 and 20\n";
return 0;
}
现在考虑以下程序:
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x >= 0) // outer if-statement
// it is bad coding style to nest if statements this way
if (x <= 20) // inner if-statement
std::cout << x << " is between 0 and 20\n";
// which if statement does this else belong to?
else
std::cout << x << " is negative\n";
return 0;
}

上述程序引入了一种潜在歧义源,称为悬空elsedangling else问题。程序中的else语句究竟与外部还是内部的if语句配对?
答案是:else语句与同一代码块中最后一个未配对的if语句配对。因此在上例中,else语句与内部if语句配对,如同程序被这样编写:
#include <iostream>
int main()
{
std::cout << "Enter a number: ";
int x{};
std::cin >> x;
if (x >= 0) // outer if statement
{
if (x <= 20) // inner if statement
std::cout << x << " is between 0 and 20\n";
else // attached to inner if statement
std::cout << x << " is negative\n";
}
return 0;
}
这导致上述程序产生错误输出:

为避免嵌套if语句时的歧义,建议将内部if语句显式包裹在代码块中。这样便可将else语句无歧义地附加到内部或外部if语句上:
#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 // attached to inner if statement
std::cout << x << " is greater than 20\n";
}
else // attached to outer if statement
std::cout << x << " is negative\n";
return 0;
}

块内的else语句与内部的if语句关联,而块外的else语句则与外部的if语句关联。
扁平化(Flattening)嵌套 if 语句
嵌套的if语句通常可通过重构逻辑或使用逻辑运算符(详见第6.8节——逻辑运算符)来扁平化处理。嵌套较少的代码更不易出错。
例如,上述示例可按以下方式展开:
#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) // only executes if x >= 0
std::cout << x << " is between 0 and 20\n";
else // only executes if x > 20
std::cout << x << " is greater than 20\n";
return 0;
}

以下是另一个使用逻辑运算符在单个if语句中检查多个条件的示例:
#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) // && is logical and -- checks if both conditions are true
std::cout << "Both numbers are positive\n";
else if (x > 0 || y > 0) // || is logical or -- checks if either condition is true
std::cout << "One of the numbers is positive\n";
else
std::cout << "Neither number is positive\n";
return 0;
}

空语句
空语句null statement是一种仅由分号组成的表达式语句:
if (x > 10)
; // this is a null statement
空语句不执行任何操作。当编程语言要求必须存在语句而程序员实际不需要时,通常会使用空语句。为提高可读性,空语句通常单独成行。本章后续讲解循环结构时,我们将看到故意使用空语句的示例。
空语句很少被有意用于if语句中。然而,它们可能无意中给新手(或粗心)程序员带来麻烦。请看以下代码片段:
if (nuclearCodesActivated()); // note the semicolon at the end of this line
blowUpTheWorld();
在上面的代码片段中,程序员在if语句末尾意外添加了分号(由于分号常用于结束语句,这是常见错误)。这个看似不起眼的错误在编译时并无异常,导致代码片段的执行效果如同以下写法:
if (nuclearCodesActivated())
; // the semicolon acts as a null statement
blowUpTheWorld(); // and this line always gets executed!
警告
请注意不要用分号“终止”if语句,否则原本需要条件执行的语句将变成无条件执行(即使它们位于代码块内)。
提示
在 Python 中,pass关键字作为空语句使用。它常被用作后续将实现的代码的占位符。由于它是关键字而非符号,pass更不易被误用,且更易于检索(便于您日后轻松找到这些占位符)。for x in [0, 1, 2]: pass # To be completed in the future在 C++ 中,我们可以使用预处理器模拟参数传递:
#define PASS void foo(int x, int y) { if (x > y) PASS; else PASS; } int main() { foo(4, 7); return 0; }为保持与其他C++语句的一致性,我们的PASS需要在末尾添加分号。PASS会被预处理器移除,而末尾的分号会被编译器解释为空语句。
条件语句中的 operator== 与 operator=
在条件语句中,应使用 operator== 进行相等性判断,而非 operator=(赋值运算符)。请看以下程序示例:
#include <iostream>
int main()
{
std::cout << "Enter 0 or 1: ";
int x{};
std::cin >> x;
if (x = 0) // oops, we used an assignment here instead of a test for equality
std::cout << "You entered 0\n";
else
std::cout << "You entered 1\n";
return 0;
}
该程序可以编译并运行,但在某些情况下会产生错误结果:


事实上,该程序始终会输出结果“您输入了1”。这是因为x = 0首先将值0赋给x,随后评估x的值(此时为0),该值在布尔逻辑中表示假。由于条件始终为假,else语句始终会被执行。

浙公网安备 33010602011771号