── 章节回顾 ──
CPU 在程序中执行的具体语句序列称为程序的执行路径。直线式程序每次运行时路径完全相同。
控制流语句(亦称流程控制语句)允许程序员改变正常的执行路径。当控制流语句使程序开始执行非顺序的指令序列时,称为一次“分支”。
条件语句用于指定其关联语句是否应当执行。
if
语句在条件为真时执行关联语句;else
语句在条件为假时执行;- 可将多个
if
与else
链式组合。 - “悬垂 else”指
else
与哪个if
配对出现歧义;悬垂else
会与同一作用域内最后一个未匹配的if
配对。因此,将if
语句体置于代码块中即可避免悬垂 else。
空语句仅由一个分号构成,什么也不做;当语法要求存在语句而程序员无需其执行任何操作时,可使用空语句占位。
switch
语句为在多项匹配值中进行选择提供了更简洁、高效的手段,仅适用于整型。case
标签用于标识待匹配值;若找不到匹配 case
,则执行 default
标签下的语句。
- 当执行流从某标签下流入下一标签下的语句时,称为“贯穿(fallthrough)”。可用
break
(或return
)防止贯穿,也可用[[fallthrough]]
属性显式标记有意的贯穿。
goto
语句允许程序跳转到代码中任意位置(向前或向后)。通常应避免使用,以免产生“意大利面条代码”——执行路径如同一碗缠绕的面条。
while
循环使程序在条件为真时反复执行。条件在循环开始前求值。
- 无限循环指条件恒为真的循环;除非其他控制流语句介入,否则会永远执行。
- 循环变量(亦称计数器)是用于记录循环执行次数的整型变量;每次循环执行称为一次“迭代”。
do-while
循环与 while
类似,但其条件在循环体执行后求值。
for
循环最为常用,适用于需固定次数循环的场景。
- 差一错误指循环次数多一次或少一次。
break
语句可立即跳出 switch
、while
、do-while
、for
(以及尚未介绍的范围 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;
}