📄 第11章 循环语句.htm
字号:
<P>}
<P>
<P>在上面例子,由于用户的两次输入我们都采用变量 c (char 类型)接收。但如果第一次输入
字母‘Y’时,循环需继续,但如果用户是在第二次输入‘Y',则表示是真的不统计了,循环却必须结束;所以,此时while无法仅凭c的值来做出正确判断,但,采用break,正如上面代码,我们在合适的位置安排一个break,从而直观地实现了。
<P>
<P>当然,这里仅为了讲学方便而举此例,如果你真的在程序中为了一个“是否继续统计”而问了用户两遍,可能会被用户骂做“神经质”。不过,如果是删除某些重要数据(直接删除,不可恢复的情况),多问一次就选得很重要了。(比如句神英语删除用户操作就会在最后多问一句“真的要说再见吗?我们会想你的……”)
<P>
<P>
<P>再举一例,看我们前面关于跑步的例子:
<P>
<P>while(已跑的圈数 < 3 )
<P>{
<P> 跑一圈……;
<P>
<P> if(我身体感觉不妙)
<P> <B>break;</B>
<P>}
<P>
<P>这段代码有点问题,因为判断“我身体感觉不妙”是在跑完一圈之后……很可能我在某一圈刚开始跑时就觉得肚子剧痛,极可能是得阑尾炎啊!按照这段程序,我只有坚持跑完一圈后,才能break了……
<P>要完美解决这个问题,我们将在本章再后讲到,现在先采用一个“通融”的办法,我们允许你每跑100米就检查一次吧:
<P>
<P>while(已跑完图数 < 3)
<P>{
<P> 跑第1个100米;
<P>
<P> if(我身体感觉不妙)
<P> <B>break;</B>
<P>
<P> 跑第2个100米;
<P>
<P> if(我身体感觉不妙)
<P> <B>break;</B>
<P>
<P> 跑第3个100米;
<P>
<P> if(我身体感觉不妙)
<P> <B>break;</B>
<P>
<P> 跑第4个100米;
<P>
<P> if(我身体感觉不妙)
<P> <B>break;</B>
<P>}
<P>代码中,我们将1圈拆为4个100米,每跑完1/4,我们就检查一次是否身体不对。看明白这个例子,我想你对break的用途和用法,可以算是理解了。
<P>
<H4><A name=11.1.2>11.1.2</A> break 的一个“高级用法”</H4>
<P>
<P>本小节不是很适于没有多少实际编程经历的初学者,所以初学者可以跳过,以后再回头阅读。当然,所谓的“高级用法”的确是应该加对引号的,所谈的内容只是一个高手们常用小小技巧。
<P>
<P>使用do...break...while简化多级条件判断的结构。
<P>
<P>如果你写过不少代码,那么一定会不时遇到类似下的情况:
<P>假设要找到文件A,复制该文件为B;然后打开B文件,然后往B文件内写入一些内容;最后在写入成功后,我们需要再进行一些相关操作。
<P>在此过程,遇到以下情况时将放弃后续的操作,认为是操作失败:
<P>1、如果A文件不存在;
<P>2、如果B文件已经存在,并且询问用户是否覆盖时,用户回答“不”;
<P>3、无法复制出B文件;
<P>4、无法打开B文件;
<P>5、无法写入B文件;
<P>6、无法正常关闭B文件。
<P>
<P>用伪代码写该段程序为:
<P>
<P>if( A文件存在 )
<P>{
<P> 执行A文件的相关操作;
<P> if( B文件不存在 || 用户允许覆盖原有B文件)
<P> {
<P> 复制A文件为B文件;
<P> if(复制文件成功)
<P> {
<P> 打开B文件;
<P> if(打开文件成功)
<P>
{
<P>
写入文件;
<P> if(写入成功)
<P> {
<P>
关闭B文件;
<P>
if(关闭成成功)
<P> {
<P>
执行其它必须在一切成功后进行的操作。
<P> ……
<P>
}
<P>
}
<P>
}
<P> }
<P> }
<P>}
<P>
<P>可能有些操作和判断可以同时处理,但这个程序的繁琐仍然不可避免,而现实中程序的复杂性往往要远过于此例。从语法上看,这个例子没有任何错误,但它的一层套一层的条件判断却让人难以书写,阅读,调试,在复杂的情况就容易造成人为的错误(比如最马虎的,花括号匹配不对等……)。
<P>
<P>同样一段代码“程序老鸟”是这样写的:
<P>
<P>do</P>
<P>{</P>
<P> if(A文件不存在)</P>
<P> break;</P>
<P> 执行A文件的相关操作;
<P> </P>
<P> if(B文件存在 && 用户不允许覆盖)</P>
<P> break;</P>
<P> </P>
<P> 复制A文件为B文件;</P>
<P> if(复制不成功)</P>
<P> break;</P>
<P> </P>
<P> 打开B文件;</P>
<P> if(打开B文件不成功)</P>
<P> break;</P>
<P> </P>
<P> 写入文件;</P>
<P> if(写入文件不成功)</P>
<P> break;</P>
<P> </P>
<P> 关闭B文件;</P>
<P> if(关闭不成功)</P>
<P> break;</P>
<P>
<P> 执行其它必须在一切成功后进行的操作。
<P> ……
<P>}</P>
<P>while(false);</P>
<P>
<P>看,代码是不是“直”了很多?这里用了do..while,可是根本不是为了循环,而是为了使用它的break功能。每当有操作不成功,就直接用break跳出循环。所以循环条件总是一个“永假”
false。
<P>在一个程序中,这种结构相当的多,为了更加一步淡化while的原来的循环用途,我们非常值得在代码加入两个共用的宏:
<P>#define BEG_DOWHILE do {
<P>#define END_DOWHILE } while(false);
<P>
<P>这里举的是do...while结构,在某些情况下,可以使用while...来实现类似功能。
<P>
<H4><A name=11.1.3>11.1.3</A> break 在for循环中的一点注意</H4>
<P>
<P>前面举的例子都是do...while或while,break在for循环也一个样。请看下面例题:
<P>
<P><B>例一:</B>从1开始累加,每次递增1,请问累加到哪个数,累加和超过2000?请输出该数,及当时的累加和。
<P>
<P><B>分析:</B>和求1~100的累加和类似,只是在发现累加和已经超过2000时,就输出当前累加的数,然后结束循环。
<P>
<P>for(int i=1,sum=0;;i++)
<P>{
<P> sum += i;
<P> if(sum > 2000)
<P> {
<P> cout << i << ","
<< sum << endl;
<P> break;
<P> }
<P>}
<P>
<P>输出结果为:
<P>
<P><FONT color=#ffffff><SPAN
style="BACKGROUND-COLOR: #000000">63,2016</SPAN></FONT>
<P>
<P>关于这段例子,需要注意三点:1、循环条件初始的位置,我们同时声明两个变量;2、没有循环条件。为了解这两点注意,请看下面放大图:
<P><IMG height=244 src="第11章 循环语句.files/ls11.h2.gif" width=662 border=0>
<P>
<P>最后一点注意是关于break和“条件因子变化”的注意。我们知道,for每执行一遍循环体后,都将执行一次“条件因子变化”语句(见上图③)。现在需要注意的是:
<P><B>在for循环中,执行break后,“条件因子变化”语句同样被跳过,没有被执行循环就被中断。</B>
<P>(完整代码请见lz1.bpr)
<P>
<P>至此,break 在
while,do...while,for中的用法我们都已见过。不过,你还记得吗,我们最早学到break是在哪里?在讲条件分支语句中switch里。如果你有点忘了那里的break是起什么作用,现在就去看看吧。
<P>
<H4><A name=11.1.4>11.1.4</A> 多层循环中的break</H4>
<P>
<P>break 只能跳出当前层的循环,所以,如果有多层循环,则在内层的break跳出循环后,外层的循环还将继续。
<P>
<P>前面说跑步的例子,一圈400米,我们每跑100检查一下是否肚子疼什么的,如果疼得利害就break,不跑了。这和现实不符,我们应该每跑一步就检查一次是否肚子疼最合理。
<P>一圈得分成几步呢?显然不能再像上面分成四次检查那样写代码了。我们加一层循环,也就是把跑一圈的工作用一个循环来实现:
<P>
<P>while(一圈未结束)
<P>{
<P> 跑一步;
<P>}
<P>
<P>然后,我们在每跑完一步时加入一个判断:
<P>
<P>while(一圈未完)
<P>{
<P> 跑一步;
<P>
<P> if(我身体感觉不妙)
<P> <B>break;</B>
<P>}
<P>
<P>把这跑一圈的代码加入外层循环:
<P>
<P>while(已跑完图数 < 3)
<P>{
<P> while(一圈未完)
<P> {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -