【c++】【基础】【primer_plus】【第五章】循环语句
前言
顺序、选择、循环,是无论任何语言都必须要实现的机制,有了这三种语句,我们才有可能实现比较复杂的逻辑。本章便是对c++语言的循环语句进行简单的介绍。
循环语句的意思就是可以重复执行某些语句。比如,我们要计算一个整型数组所有元素的和,或者我们想计算10的阶乘等,这都需要重复相同的逻辑,只不过输入的值不同罢了。
c++主要有for循环
、while循环
、do_while循环
等最为常用。c++11标准增加了foreach循环
使其运用更加灵活。
for循环
for循环
的一般格式如下。
1 | for(init; test; update) { // 初始化; 测试条件; 更新(步长) |
下面是一些例子。
1 | for(int i = 0; i < 10; ++i) { |
1 | for(int i = 0; i <= 10; i += 2) cout << i << endl; |
1 | for(int i = vi.size()-1; i >= 0; --i) cout << vi[i] << endl; |
可以看出,for循环
的初始化语句可以用来声明变量,而测试条件则是一个逻辑表达式,最后一个步长表示变量在每一步的变化。其执行过程大致如下。
先执行初始化语句。
再执行判断语句。此时如果判断语句为真,则执行循环体内代码,否则结束,跳出循环。
当循环体执行完后,执行步长更新语句,更新相关变量。
步长更新语句执行完后回到第二步,重新执行判断语句,依次循环,直到跳出。
需要注意的是,for循环
中的三条表达式都是可以省略的,即下面的语句也是合法的,它会一直输出hello world
,即死循环。也可以看出省略的判断语句默认为true
。
1 | for( ; ; ) { cout << "hello world"; } |
递增与递减
1 | int a = 5; |
1 | int a = 5; |
如上代码所示,递增运算符++
和递减运算符--
都用来表示一个变量递增或者递减一个单位。但是结果却有一些区别,这里以递增++
为例。
递增++
分为两类,一类为前缀++
,一类为后缀++
。其区别如下。
前缀
++
表示先进行加一操作,再以当前值计算表达式,形如++a
。后缀
++
表示先以当前值计算表达式,再进行加一操作,形如a++
。
上述代码中,b = ++a
等价于如下代码。
1 | a = a + 1; |
而b = a++
则等价于如下代码。
1 | b = a; |
注意,同一条语句尽量不要使用多个++
,容易引起在不同的系统上(不同的编译与汇编原理)将会有不同的结果。
1 | x = 2 * x++ * (3 - ++x); // 在我的系统上输出为0 |
从效率上来讲,推荐使用前缀++
,因为后缀++
的实现需要复制一个副本进行加一操作后再返回副本。
foreach循环
foreach循环
是c++11标准增加的新的循环方式,它在一定程度上是对for循环
的一种升级。其一般格式如下。
1 | for(type element_name : array_name) { // 元素类型 元素名称 : 数组名称 |
具体实例如下。
1 | int a[5] = {1, 2, 3, 4, 5}; |
其中int
为数组中元素的类型,i
为数组的某个元素,它会遍历数组(或其他stl容器)的每一个元素,而冒号:
后面的便是想要遍历的数组或容器。
若要修改原始数据的话可以使用引用(后面章节会讲到引用)。
1 | for(int& i : a) i += 1; |
也可结合初始化表使用。
1 | for(int i : {1, 2, 3}) cout << i << endl; |
while循环
1 | init; // 初始条件 |
如上代码为while循环
的一般格式,其中init
、test
、update
语句分别与for循环
的相对应。其执行过程大致如下。
首先执行初始化语句。
然后执行测试条件语句。如果测试条件为
true
,则进入循环体,循环体内大多时候都包含有步长更新语句(不一定在尾部)。如果测试条件为false
,则不进入循环体。一遍循环体执行结束之后,将继续执行测试条件,然后循环执行,直至跳出。
具体实例如下。
1 | int i = 0; |
再来举一个复杂一点的例子,我们使用while循环
配合<ctime>
头文件提供的api来编写带有延迟功能的循环。
1 |
|
这段代码会在开始之后御延迟delay
时间才会输出done
。
do_while循环
与while循环
不同的是,do_while循环
是一种出口条件循环,即它会先执行循环体,再进行测试语句判断。其一般格式如下所示。
1 | init; |
具体实例如下。
1 | int i = 0; |
可以看出,无论如何,do_while循环
的循环体至少都要执行一遍,这也是它与while循环
最大的区别,有时候能够合理地利用这一特征可以帮助简化某些特定的问题,尤其是某种至少需要执行一遍的重复操作。
跳出循环
我们使用break
关键字和continue
关键字跳出循环。
break
直接跳出循环体。
continue
跳出当前执行的这一轮循环体,重新开始下一轮。
循环和文本输入
我们经常使用while循环
来持续输入文本,尤其是在打acm竞赛的时候。但是接下来的格式与acm的输入不同,主要解释一般的输入问题。
那么最重要的便是如何判断输入结束。一般我们会使用某种哨兵字符,即当输入该字符时结束输入。如下代码所示。
1 | char ch; |
当然,cin
也自带了用于检测输入是否结束的标记,我们可以使用cin.eof()
或者cin.fail()
来判断输入是否已经结束,如下代码所示。
1 | char ch; |
除此之外,cin
本身也可转为bool
值作为判断输入是否结束的依据。
1 | char ch; |
这也是打acm或者刷题时经常使用的输入多组样例的方法,如下所示。
1 | while(cin >> a >> b) { |
嵌套循环和二维数组
顺序、分支、循环这三种语句组成了复杂的逻辑,当然可以相互嵌套,所以循环可以嵌套也很容易理解。下面举一个嵌套二层循环以输出二维数组的例子。
1 | int a[2][3] = { // 二行三列 |
输出结果如下。
1 | 1 2 3 |