9-x 第九章总结与测验
章节回顾
范围蔓延scope creep是指项目能力超出项目启动或项目阶段初始设定的预期范围。
软件验证software verification是测试软件在所有情况下是否按预期运行的过程。单元测试unit test旨在隔离测试代码的局部片段(通常为函数或调用),确保特定行为符合预期。单元测试框架Unit test frameworks可帮助组织单元测试。集成测试integration testing则检验多个单元组合后的协同工作状态。
代码覆盖率code coverage指测试过程中执行的源代码比例。语句覆盖率statement coverage表示测试流程触发的程序语句占比;分支覆盖率branch coverage表示测试流程执行的程序分支占比。循环覆盖率loop coverage(亦称0-1-2测试)要求:当存在循环时,需确保其在0次、1次及2次迭代时均能正常运行。
正常路径happy path指未发生任何错误时的执行路径。异常路径sad path指发生错误或失败状态的路径。不可恢复错误non-recoverable error(也称致命错误fatal error)是严重到导致程序无法继续运行的错误。能良好处理错误情况的程序具有健壮性robust。
缓冲区buffer是为数据临时存储而预留的内存区域,用于在数据传输过程中暂存数据。
检查用户输入是否符合程序预期的过程称为输入验证input validation。
std::cerr是专用于错误消息的输出流(类似于 std::cout)。
先决条件precondition是指在执行某段代码前必须始终成立的条件。不变量invariant是指在某个组件执行期间必须成立的条件。后置条件postcondition是指在代码执行后必须始终成立的条件。
断言assertion是除非程序存在缺陷否则为真的表达式。在C++中,运行时断言通常通过预处理宏assert实现。非调试代码中通常会禁用断言。static_assert是编译时评估的断言。
断言应用于记录逻辑上不可能发生的情况,而错误处理应用于应对可能发生的情况。
测验时间
问题 #1
在第8.x课——第8章总结与测验中,我们实现了猜大小游戏。
请更新原有解决方案,处理以下情况:无效猜测(如'x')、超出范围的猜测(如0或101)、或包含多余字符的有效猜测(如43x)。同时需处理用户在游戏询问是否继续时输入的额外字符。
提示:请单独编写函数处理用户输入猜测值(并包含相关错误处理)。
显示方案
#include <iostream>
#include <limits> // for std::numeric_limits
#include "Random.h" // https://www.learncpp.com/cpp-tutorial/global-random-numbers-random-h/
int getGuess(int count, int min, int max)
{
while (true) // loop until user enters valid input
{
std::cout << "Guess #" << count << ": ";
int guess {};
std::cin >> guess;
bool success { std::cin };
std::cin.clear(); // put us back in 'normal' operation mode (if needed)
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // remove any extra input
// If we didn't extract anything or the extracted guess is out of bounds, try again
if (!success || guess < min || guess > max)
continue;
return guess;
}
}
// returns true if the user won, false if they lost
bool playHiLo(int guesses, int min, int max)
{
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";
int number{ Random::get(min, max) }; // this is the number the user needs to guess
// Loop through all of the guesses
for (int count{ 1 }; count <= guesses; ++count)
{
int guess{ getGuess(count, min, max) };
if (guess > number)
std::cout << "Your guess is too high.\n";
else if (guess < number)
std::cout << "Your guess is too low.\n";
else // guess == number, so the user won
{
std::cout << "Correct! You win!\n";
return true;
}
}
// The user lost
std::cout << "Sorry, you lose. The correct number was " << number << '\n';
return false; // if the user lost
}
bool playAgain()
{
// Keep asking the user if they want to play again until they pick y or n.
while (true)
{
char ch{};
std::cout << "Would you like to play again (y/n)? ";
std::cin >> ch;
// clear out any extraneous input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
switch (ch)
{
case 'y': return true;
case 'n': return false;
}
}
}
int main()
{
constexpr int guesses { 7 }; // the user has this many guesses
constexpr int min { 1 };
constexpr int max { 100 };
do
{
playHiLo(guesses, min, max);
} while (playAgain());
std::cout << "Thank you for playing.\n";
return 0;
}

浙公网安备 33010602011771号