章节目录

常见的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(); // 这一行永远能执行到

条件表达式中,运算符== 与 运算符=

在条件表达式中测试相等性时,应该使用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语句总是执行。


8.1 If语句与代码块

上一节

8.3 Constexpr if语句

下一节