8.x — 第 8 章总结和测验

章节回顾

CPU 在程序中执行的特定语句序列称为程序的执行路径。一个直线程序每次运行时都采用相同的路径。

控制流语句(也称为流控制语句)允许程序员改变正常的执行路径。当控制流语句导致程序开始执行某些非顺序指令序列时,这被称为分支

条件语句是指定某些相关语句是否应该执行的语句。

If 语句允许我们根据某个条件是否为true来执行相关语句。如果相关条件为false,则执行Else 语句。您可以将多个 if 和 else 语句链接在一起。

else 语句与哪个if 语句相关联不明确时,就会出现悬空 else悬空 else语句与同一块中最后一个不匹配的if 语句匹配。因此,我们通过确保if 语句的主体放在一个块中来简单地避免悬空 else语句。

空语句是仅由分号组成的语句。它什么也不做,当语言要求存在语句但程序员不需要该语句做任何事情时使用。

Switch 语句提供了一种更简洁、更快的方法来在多个匹配项之间进行选择。Switch 语句仅适用于整数类型。Case 标签用于标识要匹配的评估条件的值。如果找不到匹配的 case 标签,则执行default 标签下的语句。

当执行从标签下的语句流向后续标签下的语句时,这被称为穿透break 语句(或return 语句)可用于防止穿透。[[fallthrough]] 属性可用于记录有意穿透。

Goto 语句允许程序跳转到代码中的其他位置,无论是向前还是向后。这些通常应该避免,因为它们可能创建意大利面条式代码,即当程序的执行路径类似于一碗意大利面条时发生的情况。

While 循环允许程序在给定条件评估为true时进行循环。条件在循环执行前进行评估。

无限循环是指条件始终评估为true的循环。这些循环将永远循环,除非使用其他控制流语句来停止它们。

循环变量(也称为计数器)是用于计算循环执行次数的整数变量。循环的每次执行称为一次迭代

Do while 循环类似于 while 循环,但条件在循环执行后而不是之前进行评估。

For 循环是最常用的循环,当您需要循环特定次数时,它们是理想的选择。当循环迭代次数多一次或少一次时,就会发生差一错误

Break 语句允许我们跳出 switch、while、do while 或 for 循环(也包括基于范围的 for 循环,我们尚未涵盖)。Continue 语句允许我们立即进入下一次循环迭代。

停止允许我们终止程序。正常终止意味着程序以预期的方式退出(并且状态码将指示它是否成功)。std::exit()会在main结束时自动调用,或者可以显式调用它来终止程序。它会进行一些清理,但不会清理任何局部变量,也不会展开调用堆栈。

当程序遇到某种意外错误并不得不关闭时,就会发生异常终止。可以调用std::abort进行异常终止。

算法是可用于解决某个问题或产生某个有用结果的有限指令序列。如果算法在调用之间保留某些信息,则认为它是有状态的。相反,无状态算法不存储任何信息(并且在调用时必须获得其工作所需的所有信息)。当应用于算法时,术语状态指的是有状态变量中当前持有的值。

如果算法对于给定的输入(为start提供的值)将始终产生相同的输出序列,则认为该算法是确定性的

伪随机数生成器 (PRNG)是一种生成其属性模拟随机数序列的数字序列的算法。当实例化 PRNG 时,可以提供一个初始值(或一组值),称为随机种子(或简称种子)来初始化 PRNG 的状态。当 PRNG 用种子初始化时,我们说它已经播种。种子值的大小可以小于 PRNG 状态的大小。发生这种情况时,我们说 PRNG 已经欠播种。PRNG 开始重复自身之前的序列长度称为周期

随机数分布将 PRNG 的输出转换为其他数字分布。均匀分布是一种随机数分布,它以相等的概率在两个数字 X 和 Y(包括)之间产生输出。

小测验时间

警告:从现在开始,测验会变得越来越难,但你可以做到。让我们好好完成这些测验!

问题 #1

在第4.x — 第 4 章总结和测验中,我们编写了一个程序来模拟一个球从塔上掉落。由于我们还没有循环,球只能下落 5 秒。

获取下面的程序并修改它,使球下落所需秒数,直到它到达地面。更新程序以使用所有涵盖的最佳实践(命名空间、constexpr 等)。

#include <iostream>

// Gets tower height from user and returns it
double getTowerHeight()
{
	std::cout << "Enter the height of the tower in meters: ";
	double towerHeight{};
	std::cin >> towerHeight;
	return towerHeight;
}

// Returns the current ball height after "seconds" seconds
double calculateBallHeight(double towerHeight, int seconds)
{
	const double gravity { 9.8 };
    
	// Using formula: s = (u * t) + (a * t^2) / 2
	// here u (initial velocity) = 0, so (u * t) = 0
	const double fallDistance { gravity * (seconds * seconds) / 2.0 };
	const double ballHeight { towerHeight - fallDistance };

	// If the ball would be under the ground, place it on the ground
	if (ballHeight < 0.0)
		return 0.0;
    
	return ballHeight;
}

// Prints ball height above ground
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";
}

// Calculates the current ball height and then prints it
// This is a helper function to make it easier to do this
void calculateAndPrintBallHeight(double towerHeight, int seconds)
{
	const double ballHeight{ calculateBallHeight(towerHeight, seconds) };
	printBallHeight(ballHeight, seconds);
}

int main()
{
	const double towerHeight{ getTowerHeight() };

	calculateAndPrintBallHeight(towerHeight, 0);
	calculateAndPrintBallHeight(towerHeight, 1);
	calculateAndPrintBallHeight(towerHeight, 2);
	calculateAndPrintBallHeight(towerHeight, 3);
	calculateAndPrintBallHeight(towerHeight, 4);
	calculateAndPrintBallHeight(towerHeight, 5);
       
	return 0;
}

显示答案

问题 #2

素数是大于 1 的自然数,只能被 1 和自身整除(没有余数)。

使用 for 循环编写isPrime()函数来完成以下程序。成功后,程序将打印“Success!”。

// Make sure that assert triggers even if we compile in release mode
#undef NDEBUG

#include <cassert> // for assert
#include <iostream>

bool isPrime(int x)
{
    return false;
    // write this function using a for loop
}

int main()
{
    assert(!isPrime(0)); // terminate program if isPrime(0) is true
    assert(!isPrime(1));
    assert(isPrime(2));  // terminate program if isPrime(2) is false
    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;
}

相关内容

assert是一个预处理器宏,如果关联的参数评估为 false,它会终止程序。因此,当我们写assert(!isPrime(0))时,我们的意思是“如果 isPrime(0) 为 true,则终止程序”。我们将在第9.6 — Assert 和 static_assert课中更详细地介绍 assert。

显示答案

额外加分题

上述解决方案中的 for 循环存在两个次优原因

  • 它检查偶数除数。我们不需要测试这些(除了 2)。
  • 它检查从 1 到x的每个数字,看它是否是除数。一个非素数(合数)必须至少有一个小于或等于其平方根的除数,因此检查x的平方根之外的除数是不必要的。std::sqrt(x)(在 <cmath> 头文件中)返回x的平方根。

对于后者,我们有两种选择:在循环之前计算std::sqrt(x),然后用循环变量与该值进行测试。或者,我们可以通过平方比较的两边来完全优化std::sqrt(x)(感谢读者 JJag 提出此建议)(如果您需要额外帮助,请参阅提示)。我们将在测验解决方案中使用后一种选择。

显示提示

更新上述解决方案以实现这两种优化。

显示答案

问题 #3

实现 Hi-Lo 游戏。首先,您的程序应选择一个介于 1 到 100 之间的随机整数。用户有 7 次机会猜测该数字。

如果用户没有猜对数字,程序应该告诉他们是猜高了还是猜低了。如果用户猜对了数字,程序应该告诉他们赢了。如果他们用完了猜测次数,程序应该告诉他们输了,以及正确的数字是什么。游戏结束时,应该询问用户是否想再玩一次。如果用户没有输入“y”或“n”,则再次询问他们。

对于本测验,假设用户输入了一个有效数字。

使用来自8.15 -- 全局随机数 (Random.h)的 Random.h 头文件。

您的输出应该如下所示

Let's play a game. I'm thinking of a number between 1 and 100. You have 7 tries to guess what it is.
Guess #1: 64
Your guess is too high.
Guess #2: 32
Your guess is too low.
Guess #3: 54
Your guess is too high.
Guess #4: 51
Correct! You win!
Would you like to play again (y/n)? y
Let's play a game. I'm thinking of a number between 1 and 100. You have 7 tries to guess what it is.
Guess #1: 64
Your guess is too high.
Guess #2: 32
Your guess is too low.
Guess #3: 54
Your guess is too high.
Guess #4: 51
Your guess is too high.
Guess #5: 36
Your guess is too low.
Guess #6: 45
Your guess is too low.
Guess #7: 48
Your guess is too low.
Sorry, you lose. The correct number was 49.
Would you like to play again (y/n)? q
Would you like to play again (y/n)? n
Thank you for playing.

额外加分:将最小值、最大值和猜测次数设置为可配置参数。

显示答案

我们将在第9.x — 第 9 章总结和测验中为此解决方案添加错误处理。

guest
您的电子邮箱地址将不会被显示
发现错误?请在上方留言!
与勘误相关的评论在处理后将被删除,以帮助减少混乱。感谢您帮助使网站对每个人都更好!
来自 https://gravatar.com/ 的头像与您提供的电子邮箱地址相关联。
有回复时通知我:  
1.5K 评论
最新
最早 最多投票
内联反馈
查看所有评论