do-while 语句

设想这样一种场景:我们需要向用户展示一个菜单,并要求其做出选择;若用户输入了无效选项,则必须再次询问。显然,菜单及选择过程应当置于某种循环之中(以便反复提示用户,直至其输入有效数据),但究竟应选择哪一种循环?

由于 while 循环在入口处即评估条件,这种需求对它来说颇为别扭。我们可以勉强写成如下形式:

#include <iostream>

int main()
{
    // selection 必须在 while 循环外声明,以便后续使用
    int selection {}; // 值初始化为 0

    while (selection < 1 || selection > 4)
    {
        std::cout << "Please make a selection: \n";
        std::cout << "1) Addition\n";
        std::cout << "2) Subtraction\n";
        std::cout << "3) Multiplication\n";
        std::cout << "4) Division\n";
        std::cin >> selection;
    }

    // 在此处根据 selection 执行操作
    // 例如使用 switch 语句

    std::cout << "You selected option #" << selection << '\n';

    return 0;
}

然而,这种方法仅因我们将 selection 的初值设为 0,而 0 并不在合法取值集合 {1, 2, 3, 4} 内才得以成立。倘若 0 也是合法选项,我们就必须另选一个初始化值来表示“无效”,从而把“魔数”(5.2 — 字面量)引入代码。

另一种做法是增加一个专门用于控制循环的布尔变量:

#include <iostream>

int main()
{
    int selection {};
    bool invalid { true }; // 仅用于控制循环的新变量

    while (invalid)
    {
        std::cout << "Please make a selection: \n";
        std::cout << "1) Addition\n";
        std::cout << "2) Subtraction\n";
        std::cout << "3) Multiplication\n";
        std::cout << "4) Division\n";

        std::cin >> selection;
        invalid = (selection < 1 || selection > 4);
    }

    // 在此处根据 selection 执行操作
    // 例如使用 switch 语句

    std::cout << "You selected option #" << selection << '\n';

    return 0;
}

虽然此法避免了魔数,却额外引入了一个变量,既增加了复杂度,也带来了新的出错可能。

do-while 语句

为解决上述问题,C++ 提供了 do-while 语句:

do
    statement; // 可为单条语句,也可为复合语句
while (condition);

do-while 语句与 while 循环相似,区别在于无论条件如何,循环体至少执行一次。语句执行完毕后,do-while 再检查条件;若条件为 true,则控制流跳回 do-while 顶部并再次执行。

以下示例使用 do-while 改写前述代码:

#include <iostream>

int main()
{
    // selection 必须在 do-while 循环外声明,以便后续使用
    int selection {};

    do
    {
        std::cout << "Please make a selection: \n";
        std::cout << "1) Addition\n";
        std::cout << "2) Subtraction\n";
        std::cout << "3) Multiplication\n";
        std::cout << "4) Division\n";
        std::cin >> selection;
    }
    while (selection < 1 || selection > 4);

    // 在此处根据 selection 执行操作
    // 例如使用 switch 语句

    std::cout << "You selected option #" << selection << '\n';

    return 0;
}

如此,我们既避免了魔数,也无需额外的布尔变量。

值得注意:变量 selection 必须在 do 块之外声明。若在 do 块内声明,则当 do 块结束、条件尚未评估时,该变量已被销毁;而条件表达式仍需使用该变量,因此必须将其置于 do 块之前(即使函数后续不再使用该变量亦须如此)。

实践中,do-while 循环并不常用。由于条件位于循环底部,易使循环条件不醒目,进而导致错误。因此,许多开发者建议完全避免 do-while。我们持较温和立场:在二者可选的情况下,优先使用 while 循环。

最佳实践
在可选的情况下,优先使用 while 循环而非 do-while。

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

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

公众号二维码

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