常见if语句问题

本节是《if 语句与语句块》的延续,我们将讨论使用 if 语句时常见的一些问题。

嵌套 if 语句与悬垂 else 问题

可以将 if 语句嵌套在另一个 if 语句内部:

#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";

    return 0;
}

然而,考虑以下程序:

#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                      // 这个 else 属于哪个 if?
        std::cout << x << " is negative\n";

    return 0;
}

上述代码引入了名为“悬垂 else”的潜在歧义:该 else 究竟与外层 if 还是内层 if 配对?

规则:else 与同一语句块中最后一个尚未匹配的 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                        // 与内层 if 匹配
            std::cout << x << " is negative\n";
    }

    return 0;
}

这将导致错误输出:

Enter a number: 21
21 is negative

为避免在嵌套 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
            std::cout << x << " is greater than 20\n";
    }
    else
        std::cout << x << " is negative\n";

    return 0;
}

扁平化嵌套 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)   // 仅当 x >= 0 时求值
        std::cout << x << " is between 0 and 20\n";
    else                // 仅当 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)          // && 为逻辑与,检查两条件是否均为真
        std::cout << "Both numbers are positive\n";
    else if (x > 0 || y > 0)     // || 为逻辑或,检查是否至少一个条件为真
        std::cout << "One of the numbers is positive\n";
    else
        std::cout << "Neither number is positive\n";

    return 0;
}

空语句

空语句是仅由一个分号构成的表达式语句:

if (x > 10)
    ; // 空语句

空语句不执行任何操作,常用于语法上要求存在语句而程序员无需任何动作之处。为了提高可读性,空语句通常单独成行。本章后续介绍循环时,将展示有意使用空语句的示例。

空语句很少与 if 语句配合使用,却可能因疏忽而引入错误。例如:

if (nuclearCodesActivated()); // 行尾意外加分号
    blowUpTheWorld();

由于分号的存在,代码等价于:

if (nuclearCodesActivated())
    ;                          // 空语句
blowUpTheWorld();              // 始终执行

警告

切勿在 if 语句末尾误加分号,否则原本应条件执行的语句将无条件执行,即使它们位于块内亦如此。

提示

在 Python 中,pass 关键字充当空语句,常用于占位,便于后续实现。因其为单词而非符号,误用概率低且易于搜索定位。

for x in [0, 1, 2]:
    pass               # 将来补全

在 C++ 中,可通过预处理器模拟 pass

#define PASS

void foo(int x, int y)
{
    if (x > y)
        PASS;
    else
        PASS;
}

int main()
{
    foo(4, 7);
    return 0;
}

为与其他 C++ 语句保持一致,PASS 需以分号结尾。预处理器将 PASS 移除,分号被解释为空语句。

条件表达式中的 === 误用

在条件中应使用 == 进行相等测试,而非赋值运算符 =。例如:

#include <iostream>

int main()
{
    std::cout << "Enter 0 or 1: ";
    int x{};
    std::cin >> x;
    if (x = 0) // 误用赋值而非相等比较
        std::cout << "You entered 0\n";
    else
        std::cout << "You entered 1\n";

    return 0;
}

该程序虽可编译运行,但部分情况下结果错误:

Enter 0 or 1: 0
You entered 1

事实上,程序始终输出 “You entered 1”。原因是 x = 0 先将 0 赋给 x,然后表达式求值为 x 的值 0,对应布尔值 false,故条件恒为假,else 分支始终执行。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"