你好,C++(22) 排排坐,吃果果——4.3.3 for循环:某个范围内…每个都…
4.3.3 for循环:某个范围内…每个都…
既然while语句和do…while…语句都已经可以满足我们表达循环现象的需要,那为什么C++还要专门提供for语句来表达循环现象呢?在现实世界中,常常有这样一类特殊的循环现象,例如:
在公司100000个员工范围内,每个员工都增加10000元工资;
在从1到100这个范围内,每个数字都累加到总和中。
说这些是循环现象,是因为它们的动作(增加工资、累加)会循环往复反复多次地执行。而说它们特殊,是因为这些动作总是在某个范围内(100000个员工范围内、从1到100范围内)针对其中的每一个元素执行(每个员工都增加,每个数字都累加)。在自然语言中,我们可以用“某个范围内…每个都…”这种句式来表达这类在某个范围内进行的循环现象。又因为其非常普遍,为了更方便地表达这类循环现象,所以C++才专门提供了for循环结构语句。在C++中,for循环结构的语法格式如下:
for( 初始化语句;条件判断语句;更改语句 )
{
循环体语句;
}
for循环语句所表达的是在某个范围内的循环现象,所以,其中往往有一个循环索引,它就像一个游标一样在循环范围内移动,从而可以通过它依次访问到循环范围内的各个元素。而for关键字之后的三条语句,就是对这个循环索引进行操作,使其在循环范围内按照某种规律移动,从而遍历整个循环范围。具体而言:
1. 初始化语句
初始化语句会在进入for循环语句执行时被执行一次,主要用来定义循环索引值并进行初始化,将其定位到循环范围的起始位置。也就是说,它确定的是循环范围的起点。比如,“int i = 1”就是一个典型的初始化语句,它定义了循环索引值i并将其赋值为1,也就表示这个循环是从1开始的(在C++中,我们往往用0作为循环起点)。
2. 条件判断语句
作为每次循环的开始,条件判断语句都会被执行一次,如果其值为true,会继续向下执行循环体语句。反之,则直接结束整个for循环的执行。因此,它主要用来判断循环索引值是否在循环范围的结束位置之内。如果在范围之内,条件判断语句的值就是true,for循环语句会开始下一次循环继续向下执行循环体语句。反之,如果循环索引值超出了循环范围的结束位置,条件语句的值就是false,for循环将不再继续而直接结束整个for循环。从这个意义上讲,它确定了循环范围的终点。例如,“i <= 100”就是一个典型的条件判断语句,在每次循环开始之前,它都会判断循环索引i是否在循环范围的结束位置100之内,以决定是否开始这一次循环体语句的执行,以此来将循环限定在循环范围之内。
3. 更改语句
更改语句会在每次循环体语句执行结束后被执行,主要用来对循环索引值进行修改,使其按照某种规律,逐渐地依次从循环起点变化到循环终点。在这个过程中,我们就可以根据这个不断变化的循环索引值访问这个循环范围内的每个元素,这一过程通常也被称为对循环范围内元素的遍历。例如,“++i”这个更改语句,就是让循环索引i在每次循环后增加1,使其向循环范围的结束位置移动一步。这样,循环索引i就可以从循环起点1逐渐递增到循环终点100,这样我们就有机会访问到循环范围内的每一个元素。
所谓死循环,就是指循环没有结束的机会,会一次又一次永远执行下去的循环。任何循环都必须在一定条件下结束循环,或者是因为条件判断语句的值为false而结束循环,或者是在循环内部在一定条件下用break关键字结束循环,总之一定要有结束循环的机会,否则就会成为死循环一直执行下去,导致循环后面的代码得不到执行,自然也就得不到正确的结果。例如,在前面的例子中,“0 != nInput”这个条件判断语句就有其值成为fasle的机会,那就是用户输入的nInput的值为0的时候。所以,这个循环有机会结束而不会成为死循环。
循环的结束往往是由条件判断语句决定的,所以我们在处理条件判断语句时要格外小心。如果处理不当,就可能导致无论怎么执行,其值始终是true,这样循环就永远没有机会结束而形成一个死循环。例如:
// 条件判断语句处理不当形成的死循环
// 忘掉了变更语句,但是仍能编译通过
for(int i = ; i < ;)
{
cout<<"I LOVE YOU!"<<endl;
}
这段程序的本意是想说一万遍“I LOVE YOU!”装情圣,结果却忘了在更改语句中对循环索引i进行更改,这样,循环索引i的值始终是最初的0,而条件判断语句“i<10000”的值也就始终为true,循环始终无法结束而成为一个死循环,结果就成了喋喋不休地说“I LOVE YOU!”,自然只会被人当成傻瓜了。如果不想从情圣变傻瓜,那就好好处理我们的条件判断语句,尽量避免死循环的出现。
for关键字之后的三个语句是对循环条件进行处理,那循环体语句就表达的是循环动作。在执行的时候,for循环会首先执行一次初始化语句,然后再执行条件判断语句,如果其值为true,则意味着当前循环条件满足,就会开始向下执行循环体语句,完成后,接着会执行更改语句对循环索引值进行修改,随后会再次执行条判断语句,以判断循环条件是否仍然满足,如果满足,则开始下一次循环。这个过程会不断循环下去,直到条件判断的值为false,循环条件不再满足为止。for循环的执行过程如图4-5所示。
在整个循环过程中,循环索引的值会按照某种规律依次从循环开始位置变化到循环的结束位置,这也就意味着,在每次循环中,循环索引的值是不断变化的,而利用这些不断变化的索引值,我们就可以访问到循环范围内的各个数据。例如,”nTotal += i;” 就是一个典型的循环体语句,每次循环的时候,它将循环索引值i加和到nTotal中,而循环索引值i的值又是从1(int i = 1)到100(i <= 100)逐渐递增(++i)的,这也就相当于nTotal依次加上了1、2、3…99、100,自然最后得到的就是从1到100所有整数的累加和了。
按照上面我们对for循环各个部分的分析,我们可以得出这个计算从1到100所有整数和的for循环:
// 计算从1到100之间所有整数的和
// 记录和值
int nTotal = ;
// 使用for循环,将1到100之间的整数逐个跟nTotal相加
for( int i = ; // 循环起点
i <= ; // 循环终点
++i ) // 循环索引值变化规律
{
// 将整数累加
nTotal += i;
} cout<<"1到100之间所有整数的和是"<<nTotal<<endl;
4.3.4 循环控制:break和continue
虽然循环现象会周而复始不断地执行,但也有遇到意外情况循环被打破的时候。例如:
一直不断地为祖国辛勤工作,只要我还活着。但如果生病了,只好提前退休;
公司100000位员工,除了年龄超过50岁的人之外,其余每个人的工资都增加10000元;
这里,循环现象中出现的“生病”和“年龄超过50岁”,就打破了原来的循环,属于循环现象中的例外情况,需要特殊处理,有的需要提前终止循环(生病退休),有的需要跳过循环体的执行(不增加工资)而直接开始下一次循环。为了描述循环中的例外情况,C++提供了两个关键字:break和continue。
1. break
在介绍switch并列条件选择语句时已经介绍过break关键字,它的作用就是结束整个switch语句的执行。与之类似的,当它用在循环结构中时,其作用也同样是结束当前循环控制语句,继续执行循环语句之后的下一条语句。这样,我们就可以利用它来表达那些因例外情况而需要提前结束的循环现象。例如,用它来表达因“生病”这一例外情况而“提前退休”的循环现象:
// 是否活着
bool bAlive = true;
// 是否生病
bool bSick = false; while(bAlive) // 判断是否活着
{
if(bSick) // 判断是否生病
{
cout<<"生病了提前退休"<<endl;
break; // 因为生病这一例外情况而提前结束循环
} cout<<"为祖国辛勤工作"<<endl;
// 改变循环控制条件bAlive…
} // …
在执行循环体语句的时候,会首先用if条件语句判断是否生病,也就是判断例外情况是否发生。如果例外情况发生,bSick的值会变为true,程序会进入if条件语句内部执行,当遇到break关键字之后,就会跳出循环,结束整个循环的执行。这样,if条件语句负责对是否发生例外情况进行判断,而break关键字则负责在例外情况发生的时候提前结束循环。两者结合起来,就很好地表达了那些因发生例外情况而需要提前结束的循环现象。
我们可以再来看一个实际的例子,还是那个收支统计程序,我们可以用break关键字将其改写为:
int nTotal = ;
int nInput = ; do
{
cout << "请输入你的收入或支出:";
cin>>nInput;
// 对输入的数据进行判断,
// 如果是0这种例外情况,表示输入结束,用break关键字结束整个循环
if( == nInput )
break; // 正常情况,将输入的收支数目加和到收支总数
nTotal += nInput; } while ( true ); // 用true作循环条件,表示循环会在内部因例外情况而结束
在这里,我们用true作为do…while…循环语句的条件判断语句,但这并不是一个“死循环”,因为它有结束循环的机会,那就是当用户输入的nInput为0时,程序会进入“if( 0 == nInput )”条件语句执行,遇到其中的break关键字就会结束整个循环,从而避免了成为死循环。同时,它也表达了对“输入的收支数目为0”这一例外情况的处理:结束整个循环。经过这样的改写后,循环语句可以无限地接受用户的输入,但是当用户想结束输入的时候,只需要输入0满足“0 == nInput”这个意外情况条件,执行break关键字就可以结束整个循环的执行。
2. continue
break关键字是在某种条件下结束整个循环,而continue关键字则是在某种条件下结束本次循环体(也就是跳过continue关键字之后的所有循环体语句)的执行,然后直接继续向下尝试下一次循环。如果是while或do…while…循环,会直接判断循环条件是否满足以开始下一次循环;如果是for循环,则会接着执行更改语句然后再判断循环条件是否满足以开始下一次循环。还是使用上面的收支统计例子,如果一个大款对小于10000元的小钱根本不在乎,只想统计大于等于10000的收入和支出,则可以用continue关键字将程序改写如下:
// 大款的收支统计程序
int nTotal = ;
int nInput = ; do
{
cout << "请输入你的收入或支出:";
cin>>nInput; // 如果是小于10000的小钱,不用统计在内
if( (nInput > -) && (nInput < ) )
continue; // 跳过后面的循环体语句,不进行统计 nTotal += nInput;
} while ( != nInput );
在这个大款的收支统计程序中,当nInput接收用户输入数据后,我们用if条件语句判断其数值是否小于10000。如果小于,表示这是不用统计的小钱,则执行if条件语句中的continue关键字,跳过后面的加和统计语句“nTotal += nInput;”的执行不将其统计在内,而直接跳转到对条件表达式“0 != nInput”的计算,以判断是否可以开始下一次循环。这样,就很好地表达了对“收支数目小于10000”这种例外情况的特殊处理:结束本次循环,不将其统计在内。
总结起来,break和continue常常和条件语句混合使用,条件语句负责判断是否出现例外情况,而它们则表达对例外情况的处理:break是跳出整个循环,立刻结束循环控制语句的执行;而continue只跳出本次循环,结束本次循环的执行而继续执行下一次循环。图4-6展示了break和continue之间的区别。
图4-6 break和continue之间的区别
你好,C++(22) 排排坐,吃果果——4.3.3 for循环:某个范围内…每个都…的更多相关文章
- Java练习小题_猴子吃桃问题分别用for循环和while循环实现程序。
要求说明: 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到第10天早上想再吃时, ...
- java语言描述 猴子吃桃问题(递归和循环写法)
//题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个//第二天早上又将剩下的桃子吃掉一半,又多吃了一个//以后每天早上都吃了前一天剩下 的一半零一个.到第10天早上想再 ...
- 你好,C++(12)怎样管理多个类型同样性质同样的数据?3.6 数组
3.6 数组 学过前面的基本数据类型之后,我们如今能够定义单个变量来表示单个的数据.比如,我们能够用int类型定义变量来表示公交车的216路:能够用float类型定义变量来表示西红柿3.5元一斤. ...
- 你好,C++(12)如何管理多个类型相同性质相同的数据?3.6 数组
3.6 数组 学过前面的基本数据类型之后,我们现在可以定义单个变量来表示单个的数据.例如,我们可以用int类型定义变量来表示公交车的216路:可以用float类型定义变量来表示西红柿3.5元一斤.但 ...
- [官方软件] Easy Sysprep v4.3.29.602 【系统封装部署利器】(2016.01.22)--skyfree大神
[官方软件] Easy Sysprep v4.3.29.602 [系统封装部署利器](2016.01.22) Skyfree 发表于 2016-1-22 13:55:55 https://www.it ...
- javascript中数组的22种方法
× 目录 [1]对象继承 [2]数组转换 [3]栈和队列[4]数组排序[5]数组拼接[6]创建数组[7]数组删改[8]数组位置[9]数组归并[10]数组迭代[11]总结 前面的话 数组总共有22种方法 ...
- COJN 0584 800603吃糖果
800603吃糖果 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名( ...
- 你好,C++(24)好大一个箱子!5.1.1 函数的声明和定义
第5章 用函数封装程序功能 在完成功能强大的工资程序V1.0之后,我们信心倍增,开始向C++世界的更深远处探索. 现在,我们可以用各种数据类型定义变量来表达问题中所涉及的各种数据:用操作符连接这些变量 ...
- 你好,C++(23) 4.4.2 工资程序成长记:用数组处理批量数据,用循环结构执行重复动作
4.4 从语句到程序 了解了各种表达式和语句之后,就相当于掌握了写作文要用到的词语和句子,但是,仅有词语和句子是无法构成一篇有意义的文章的.要完成一篇文章,先需要确定这篇文章的结构,是先分述再总述, ...
随机推荐
- 如何改变dreamweaver的编码方式
- mysql的mvcc(多版本并发控制)
mysql的mvcc(多版本并发控制) 我们知道,mysql的innodb采用的是行锁,而且采用了多版本并发控制来提高读操作的性能. 什么是多版本并发控制呢 ?其实就是在每一行记录的后面增加两个隐藏列 ...
- WordPress网站更换老鹰主机详细操作
眼看着之前买的虚拟主机就要到期了,本着节约至上的美德,就和同事一起买了老鹰主机.因为第一次网站的配置是一个朋友帮忙的,所以现在想完全自己动手操作,毕竟之后的博客维护还是得靠自己.下面就来和我一起学习怎 ...
- 关于LEA指令(单周期就可以做简单的算术计算)
堆栈种分配的局部变量所谓的“标号”,你以为是什么?(都是那些该死的宏惹的祸,大家要都是老老实实写代码,就不会有这些疑问了). 比如你用local在栈上定义了一个局部变量LocalVar,你知 ...
- COJN 0483 800501求最大非空子矩阵
800501求最大非空子矩阵 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩 ...
- BZOJ 1010 [HNOI2008]玩具装箱toy
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 7184 Solved: 2724[Submit][St ...
- URL图片预览(createObjectURL)
1.说明 1)createObjectURL 作用:创建url(creates a URL for the specified object); 语法:var url = URL.createObj ...
- struts接收参数方式
第一种,直接用action的属性接收,是初学者常用的方法. package com.starain.user; public class User{ private String username; ...
- 定时执行程序-Quartz简单实例
1.加jar包:Quartz自己quartz-1.8.3.jar和依赖包commons-logging.jar .slf4j-log4j12-1.5.10.jar .slf4j-api-1.5.10 ...
- java排序算法-插入排序
public class InsertSortUtils { public static void main(String[] args) { insertSortTest(); shellSortT ...