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;
}

image

上述程序引入了一种潜在歧义源,称为悬空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;
}

这导致上述程序产生错误输出:

image

为避免嵌套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;
}

image

块内的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;
}

image

以下是另一个使用逻辑运算符在单个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;
}

image


空语句

空语句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;
}

该程序可以编译并运行,但在某些情况下会产生错误结果:

image

image

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

posted @ 2026-02-25 15:55  游翔  阅读(0)  评论(0)    收藏  举报