第三节 · 对重复操作的化简 · 迭代语句

计算机本质上是个高级机械,所以它很擅长做不断重复的工作。而将枯燥乏味的各种计算工作交给计算机来办,是再合适不过的事了。

我们接下来将继续深入,探索 C++ 是如何做到循环操作的。


先来尝试一道简单的数学题:

求 1 + 2 + 3 + ... + n 的结果,其中 n 是一个正整数。

如果知道 n 是几,我们也许可以这么写,简单粗暴:

// 设 n 为 10
cout << 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 << endl;

但如果我们事先不知道 n 的值呢?

此时,就该 for 上场了:

int n, sum = 0;		// n 为输入的数字,sum 为要输出的累加数值
cin >> n;
for (int i = 1; i <= n; ++i)
{
    // 这对花括号内的内容将执行 n 遍
    sum = sum + i;	// 在第 i 遍时,将 i 累加到 sum 上
}
cout << sum << endl;

for 与先前的 if 有些相似,其后也跟着一对小括号,且小括号后也可跟单独一条语句或一对花括号组成的语句块。

它的格式如下:

小括号内的东西有点多,我们逐个分析。

首先是初始化语句。你可以在这里定义一个或多个同类型的变量。例如,定义新变量int i = 0 与赋值 ch1 = 'a', ch2 = 'b' 均是可以的。

再之后是循环条件。这里写的内容与 if 后跟的条件是一样的,是一个最终运算结果为布尔值的表达式。这个条件的运算结果将决定循环是否(再次)执行——为 true 时将执行一遍循环体,并进入下一轮判断;为 false 时则结束循环,执行循环体之后的内容。

最后的迭代操作可以是任何表达式,它在每一轮循环的结尾都会执行一次。很多时候,我们都会在此写诸如 i++j -= 2 这类自增或自减的表达式。

我们再拿刚刚的例子具体剖析:

第一部分很好理解,声明了个变量 i 并初始化为 1。值得注意的是,在 for 语句的小括号内创建的变量仅在 for 语句的循环体内有效,出了这个范围便无法使用这类变量:

第二部分与第三部分一起看,可以发现 i 由此可以从 1 数到 n

稍微变一下刚刚的例子:

注意第二部分的小于等于改成了小于。这么做会导致其改为从 1 数到 n - 1,而不是数到 n

为什么呢?我们不妨设想一下第 n - 1 次循环执行结束时的场景。在循环的末尾,先执行了 ++i,使 i 从原本的 n - 1 变为 n,然后进入下一轮循环前的判断。由于 i 现在的值是 n,已不满足 i < n 这个条件,便不再执行第 n 次循环,而继续执行循环体外的部分。而修改前的条件 i <= n 可以接受 i 等于 n 时的情况,所以可以执行第 n 次循环。

另外,for 的小括号中三个部分均可省略,例如:

哪怕三个部分一个都不写,也必须写两个分号占位。

有关无限循环的内容,我们会在后文的跳转语句部分具体了解。


除了 for 以外,我们还可以使用 whiledo...while 做到循环。相比较于 for 来讲,这两者更纯粹、更简单,因为它们只需要提供判断条件即可,不需要初始化与迭代操作。

我们先来看一下 while

当程序执行到此处时,会先检查条件。条件满足时,才会进行第一次循环,否则会连第一次循环都不执行,转而执行循环体外的下一条语句。之后便是检查条件与执行循环体的交替过程,条件失效时便不再执行循环体。

它其实也可以看作是 for 的基础版。如果我们将 for 改为以 while 实现,将会是这样的:

很明显,用 while 实现与 for 类似的功能更是费劲,而且也将原本仅在循环体内有效的变量 i 拿了出来,导致循环体外也能访问到变量 i 了。是否需要这么做,还需要看具体需求。


我们再来看一下 do...while

while 不同的是,不论条件怎样,do...while 总是会先执行一次循环体,然后再作判断。当条件不满足时仍会结束循环。

如果不好理解,你可以想象它是先无条件执行了一遍循环体,然后再执行同样条件的 while 循环:

尤其需要注意的是,do...while 的末尾一定要加分号,切记!


循环与什么最搭配呢?数组这类东西当然是最适合的了!

数组的下标是从 0 开始数起的一系列自然数,而 for 很是擅长数下标:

我们可以看到,这段程序将 i 从 0 数到 4,正好用在了选取数组 a 的共 5 个元素上。

是否有更简单的办法呢?有,方法是使用范围 for

看起来是否特别简洁?

这便是范围 for,它的格式如下:

变量名可以写成值传递的形式,也可以写成引用传递的形式。我们来看两个例子:

回忆一下先前对引用的知识,引用本质上就是对象的别名。如此一来,引用传递的意思,其实就相当于将所取得的那个元素本身传递过来,于是对此变量的各种修改也同样作用在了对应的各个元素。

值传递很好理解。在值传递模式下,每个元素都会被拷贝一次,我们对此变量的各种修改仅仅是相当于修改了对应元素的副本。因此,我们不论作出如何的修改,都不会影响到对应的元素本身。

最后再来看一下可被迭代的对象。除了数组之外,它还支持对列表初始化得到的常量列表进行遍历:

在后续章节中,我们还将了解由标准库提供的许多容器,它们也可以用在范围 for 上。


循环同样是 C++ 程序中不可或缺的一部分。forwhiledo...while 三者为我们提供了条件,使得程序进行大规模运算成为了可能。借助于现代计算机强劲的性能,我们将能由此摆脱各种繁冗纷杂的计算。

Last updated