总结与测验

── 章节回顾 ──

CPU 在程序中执行的具体语句序列称为程序的执行路径。直线式程序每次运行时路径完全相同。

控制流语句(亦称流程控制语句)允许程序员改变正常的执行路径。当控制流语句使程序开始执行非顺序的指令序列时,称为一次“分支”。

条件语句用于指定其关联语句是否应当执行。

  • if 语句在条件为真时执行关联语句;
  • else 语句在条件为假时执行;
  • 可将多个 ifelse 链式组合。
  • “悬垂 else”指 else 与哪个 if 配对出现歧义;悬垂 else 会与同一作用域内最后一个未匹配的 if 配对。因此,将 if 语句体置于代码块中即可避免悬垂 else。

空语句仅由一个分号构成,什么也不做;当语法要求存在语句而程序员无需其执行任何操作时,可使用空语句占位。

switch 语句为在多项匹配值中进行选择提供了更简洁、高效的手段,仅适用于整型。case 标签用于标识待匹配值;若找不到匹配 case,则执行 default 标签下的语句。

  • 当执行流从某标签下流入下一标签下的语句时,称为“贯穿(fallthrough)”。可用 break(或 return)防止贯穿,也可用 [[fallthrough]] 属性显式标记有意的贯穿。

goto 语句允许程序跳转到代码中任意位置(向前或向后)。通常应避免使用,以免产生“意大利面条代码”——执行路径如同一碗缠绕的面条。

while 循环使程序在条件为真时反复执行。条件在循环开始前求值。

  • 无限循环指条件恒为真的循环;除非其他控制流语句介入,否则会永远执行。
  • 循环变量(亦称计数器)是用于记录循环执行次数的整型变量;每次循环执行称为一次“迭代”。

do-while 循环与 while 类似,但其条件在循环体执行后求值。

for 循环最为常用,适用于需固定次数循环的场景。

  • 差一错误指循环次数多一次或少一次。

break 语句可立即跳出 switchwhiledo-whilefor(以及尚未介绍的范围 for)循环。
continue 语句立即进入下一次循环迭代。

终止(halt)语句用于结束程序。

  • 正常终止:程序按预期退出,状态码指示成功或失败。std::exit()main 结束时自动调用,也可显式调用以终止程序;其执行部分清理,但不销毁局部变量,也不展开调用栈。
  • 异常终止:程序遇到意外错误被迫关闭。可调用 std::abort 实现异常终止。

算法是为解决某问题或产生有用结果而制定的有限指令序列。

  • 若算法在多次调用间保留信息,则为“有状态”;否则为“无状态”。
  • 若给定输入总能产生相同输出序列,则称算法为“确定性”。

伪随机数生成器(PRNG)是一种算法,其输出序列的统计特性模拟随机数序列。实例化 PRNG 时,可提供初始值或值集(称为随机种子或种子)以初始化其状态,称为“播种”。若种子位数小于 PRNG 状态位数,则称 PRNG“欠播种”。PRNG 开始重复前的序列长度称为“周期”。

随机数分布将 PRNG 输出转换为其他分布。均匀分布是在区间 [X, Y](含端点)内等概率产生输出的随机数分布。

测验时间

提示:自本测验起难度逐步提升,但请相信你能完成!

问题 1

在第 4 章总结与测验中,我们编写了一个模拟球从塔上坠落的程序。由于当时尚未学习循环,球只能下落 5 秒。 请将下方程序修改为:球持续下落直至触地,并应用所有已介绍的最佳实践(命名空间、constexpr 等)。

#include <iostream>

double getTowerHeight()
{
    std::cout << "Enter the height of the tower in meters: ";
    double towerHeight{};
    std::cin >> towerHeight;
    return towerHeight;
}

double calculateBallHeight(double towerHeight, int seconds)
{
    const double gravity { 9.8 };
    const double fallDistance { gravity * (seconds * seconds) / 2.0 };
    const double ballHeight { towerHeight - fallDistance };
    return ballHeight < 0.0 ? 0.0 : ballHeight;
}

void printBallHeight(double ballHeight, int seconds)
{
    if (ballHeight > 0.0)
        std::cout << "At " << seconds << " seconds, the ball is at height: "
                  << ballHeight << " meters\n";
    else
        std::cout << "At " << seconds << " seconds, the ball is on the ground.\n";
}

void calculateAndPrintBallHeight(double towerHeight, int seconds)
{
    printBallHeight(calculateBallHeight(towerHeight, seconds), seconds);
}

int main()
{
    const double towerHeight{ getTowerHeight() };
    for (int sec{ 0 }; ; ++sec)
    {
        const double height{ calculateBallHeight(towerHeight, sec) };
        printBallHeight(height, sec);
        if (height <= 0.0) break;
    }
    return 0;
}

问题 2

质数是指大于 1 且仅能被 1 和自身整除的自然数。 请补全下列程序,实现使用 for 循环的 isPrime() 函数。成功后将输出 “Success!”。

#undef NDEBUG
#include <cassert>
#include <cmath>
#include <iostream>

bool isPrime(int x)
{
    if (x < 2) return false;
    if (x == 2) return true;
    if (x % 2 == 0) return false;

    for (int i{ 3 }; i * i <= x; i += 2)
        if (x % i == 0) return false;

    return true;
}

int main()
{
    assert(!isPrime(0));
    assert(!isPrime(1));
    assert(isPrime(2));
    assert(isPrime(3));
    assert(!isPrime(4));
    assert(isPrime(5));
    assert(isPrime(7));
    assert(!isPrime(9));
    assert(isPrime(11));
    assert(isPrime(13));
    assert(!isPrime(15));
    assert(!isPrime(16));
    assert(isPrime(17));
    assert(isPrime(19));
    assert(isPrime(97));
    assert(!isPrime(99));
    assert(isPrime(13417));

    std::cout << "Success!\n";
    return 0;
}

问题 3

实现 Hi-Lo 猜数游戏。程序随机选取 1–100 之间的整数,玩家有 7 次机会猜测。

  • 猜错则提示“过高”或“过低”;
  • 猜对则提示胜利;
  • 用完 7 次仍未猜中则提示失败并公布答案;
  • 每局结束询问是否再玩,输入非 'y'/'n' 则重复询问。

使用 Random.h

示例会话见原题,额外加分:将最小值、最大值及猜测次数设为可配置参数。

#include <iostream>
#include "Random.h"

void playGame(int min, int max, int guesses)
{
    int target{ Random::get(min, max) };
    for (int attempt{ 1 }; attempt <= guesses; ++attempt)
    {
        std::cout << "Guess #" << attempt << ": ";
        int guess{};
        std::cin >> guess;

        if (guess == target)
        {
            std::cout << "Correct! You win!\n";
            return;
        }
        else if (guess < target)
            std::cout << "Your guess is too low.\n";
        else
            std::cout << "Your guess is too high.\n";
    }
    std::cout << "Sorry, you lose. The correct number was " << target << ".\n";
}

int main()
{
    constexpr int min{ 1 }, max{ 100 }, guesses{ 7 };
    while (true)
    {
        std::cout << "Let's play a game. I'm thinking of a number between "
                  << min << " and " << max << ". You have " << guesses
                  << " tries to guess what it is.\n";
        playGame(min, max, guesses);

        char again{};
        do
        {
            std::cout << "Would you like to play again (y/n)? ";
            std::cin >> again;
        } while (again != 'y' && again != 'n');

        if (again == 'n')
        {
            std::cout << "Thank you for playing.\n";
            break;
        }
    }
    return 0;
}

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

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

公众号二维码

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