第四节 · 跃迁到圈外 · 跳转语句

经过先前对条件判断与条件循环的学习,我们已经可以据此构造出基本的逻辑流程了。不过,仅凭这么点工具似乎仍然不够用。

接下来,我们还将再度深入,了解更进一步的流程控制方法,让整个程序的流程变得完全可控。


先来看个简单的问题:

如何做到输入 n 个数字,再求出它们的和?

这应该不难,我们先知道n是多少,再连续接收n次数字,接收一次就累加一次:

int n;
cin >> n;						// 先获取 n
int sum = 0;					// 初始化一个存贮累加结果的变量
for (int i = 0; i < n; ++i)		// 循环 n 次
{
    int a;						// 每轮循环都新声明一个变量
    cin >> a;					// 每轮循环都接收一次数字
    sum += a;					// 将接收到的数字累加进 sum
}
cout << sum << endl;			// 输出结果

不过,如果不知道n这个确切的循环次数,这种程序就不能解决问题了。

再来看一下修改后的问题:

如何做到输入若干个数字,当某次输入的数字为 0 时就结束输入,再求出它们的和?

由于输入数字的数量是未知的,我们需要不断地获取输入,这就需要无限循环地执行获取输入与累加的过程。但同时,我们又需要再输入的数字为 0 时结束循环。

仅凭单纯的循环与判断实现这样的逻辑很是麻烦。现在,我们尝试一下更简便的做法:

break 用于跳出当前所在的循环体,可以在 forwhiledo...while 中使用。在这个例子中,我们在一句if内使用了 break,使得循环得以在特定条件下主动跳出。

要使用break,只需要保证它是在某个可被跳出的语句块内,没有其它限制。下面的例子展示了其跳出循环体的能力:


很多时候,break 被用于跳出死循环,或也可以称为无限循环。顾名思义,这种循环是无法自发停止的。

要写出一个死循环,只需要保证循环条件始终为真(true)就可以了:

死循环可用于不定量数据的输入、输出与不间断的数据监视、数据处理等。很明显,这类死循环在外界条件发生变化时,便需要使用 break 结束循环,例如数据全部读写完成、用户发起了停止的指令等。


有时候,我们需要在循环不结束的情况下,只结束这一轮的循环,这类需求并不少见。我们来看个具体的问题:

请列举 200 以内的素数

素数是什么?只能被这个数本身和 1 整除的大于 1 的自然数就是素数。像 2、3、5、7、23、51 这类就是素数,而像 4、6、10、30 这类很明显可以被其它数字整除的数字就不是素数。

根据以上的概念,我们可以确定基本思路,是将每个数字都拿来试除一遍。只要出现一次余数为 0 的情况,就可以断定它不是素数。

具体的实现如下:

这个程序先定义了一个很大的数组,用于存储这 200 为数字是否为素数的标识。外围的循环从 2 数到 199,列举每个数字;内围的循环则是从 2 数到这个数字的前一个数字,分别将它们作为除数与这个数字相除。当列举的所有数字部都无法整除它时,就可以断定它是一个素数了。

不过,这个程序还有可以改进的空间。在刚刚的程序中,我们将从 2 到 i - 1 的每个数字都用了一遍,但实际上我们只需要拿素数作除法就可以了:

continue 用于结束其所在循环体的本轮循环。它与 break 的区别在于,break 会直接结束整个循环,而 continue 则不会结束整个循环,仅仅是结束这一轮循环而已,下一轮循环会立即开始。

它的使用条件与 break 也没有太大的出入:

回到刚刚过滤素数的例子。从数学角度来看,要知晓一个数字是否为素数,只需要将其与比此数字小的所有数字相除一遍就可以了,无需连同非素数也来一遍——重复的非素数与其之前的部分素数有公因数,因此只除以一遍这个素数便足矣。

所以,continue 在修改后程序中的作用就很明显了,其实就是判断不为素数为真的情况下,结束此轮循环,避免无用的运算。在执行下一轮循环前,for 语句中的 ++j 会照常执行。


也许,ifelse 够我们拿来用作判断了,但碰到大批量判断某个变量的各种值时,一个一个地写 ifelse 实在是很费事:

幸好,C++ 提供了 switch,它可以帮助我们轻松地书写大规模对同一个变量的判断逻辑:

switch 后跟一对小括号,其中是欲判断的变量。在这之后的一对花括号内有若干个以 case 为开头、冒号为末尾的标记,其中 case 后以空格隔开一个常量switch 语句会执行其中一个 case 标记后的语句,执行哪一个取决于被判断的变量与其中哪个标识对应的常量相等。从寻到的标记开始,除非遇到 break 语句,否则将会一直执行到 switch 语句块的末尾。

它的格式是这样的:

default 用于处理被判断的值不等于 switch 中任意一个 case 后跟的变量的情况。一般来讲,我们都应当在 switch 中写一个 default 标识,哪怕真的没啥事可做:

为什么非得留个 default 呢?这算是一种良好的习惯,它可以帮助后来阅读与修改这个程序的人(包括你自己)完整理解这段选择逻辑的行为,不至于出现错误的改正。用大白话讲,如果没加 default 又被后来者看到了,他很可能会补上一个 default,并添加一些违背原作者意愿的逻辑,得不偿失。

break 不光可用于跳出循环体,也可以用于跳出 switch 语句块。有些人会想当然地以为,从一个 case 开始,执行到下一个 case 时,会自动跳出 switch,实际上却不是这样:

这段程序执行后,三行 cout 都会被执行!所以,要想各个 case 互不干扰,一定要记得在各段 case 的末尾加 break

这种特性并非一无是处。如果我们需要整合一批 case 执行同一批逻辑,使用刚刚所谓不停执行的特性会方便许多:


至此,我们便掌握了一切在 C++ 中实现结构化程序逻辑的基本工具。它们是程序中最基本的组成部分,熟练使用它们,可以帮助你构筑无限的可能!

Last updated