break的作用与用法

来源:互联网 发布:python 字符串转日期 编辑:程序博客网 时间:2024/05/17 08:23

11.1.1 break的作用与用法

 

循环就象绕圈子。比如,体育课,跑1200米,跑道一圈400米,所以我们要做的事就是一边跑一边在心里计数(当然要已数,否则老师万一少计一圈,我们可就玩完了),当计数到3圈时,“循环”结束。

如果,我在跑步时不幸由于体力不支而晕倒……怎么办?

 

有两种办法,一种是在判断是否继续循环的条件中加入新增条件的判断:

假设原来的循环表达为:

 

while(已跑完的圈数 < 3)

{

跑一圈……;

}

 

那么,加上附加条件后,循环表达为:

 

while(已跑完的圈数 <3 && 我还跑得好好的) //&& 就是"并且",没忘吧?

{

跑一圈……

}

 

第二种方法是在循环中使用条件分支,在指定的条件成立时,中途跳出循环,用于实现跳出的关键字为:break。

 

while(已跑的圈数 < 3 )

{

跑一圈……;

  

if(我身体感觉不妙)

     break;  

}

 

在循环中,每跑完一圈,都检查一下自已是否感觉不妙,如果是,则程序执行break,直接跳出while,而不管此时圈数是否到达3圈。

 

还记得“小女孩买裙子”的故事吗?那时候,我们将“父母不给买小红裙 && 我还没有哭累”作为循环继续的条件,如果使用break,则可以写成这样:

while(父母不给买小红裙)

{

我哭;

  

if(我哭累了)

    break;

}

 

在循环中,“我”每哭一次,都想想是否累了,如果是,则程序执行break,直接跳出while,而不管此时爸妈是否已经买了我的裙。

 

通过这两个例子,你应该注意到了,如果要用break,则if的条件(也就是要执行break分支的条件),正好是把原来放在循环判断中的条件反正过来。比如,原来是判断“我还跑得好好的”,现在则是判断“我身体感觉不妙”;原来是判断“我还没有哭累”,现在是判断“我哭累了”。

一句话,原来是判断“是否继续循环”,现在是判断“是否跳出循环”……

 

再来看那个“可以多次统计”的统计程序。看看是否也能把它改成使用break来结束循环。

为了节省篇幅同时也是为了突出重点,我们将其中用于实现一次统计的代码,用一句伪代码来实现。(什么叫伪代码?我们用得很经常啊,就是那些用自然语言写的“代码”,这些代码当然无法在计算机上运行,它们只是要方便地表达实际代码要实现的功能)。

 

int main(int argc, char* argv[])

{

   实现统计一个学员的成绩; //伪代码,详细代码请见上章相关部分

 

  do

   {

      //提问是否继续统计:  

      cout <<"是否开始新的统计?(Y/N)?";

      cin >> c;

     }

     while( c == 'y' || c == 'Y');

}

 

改成用 break;

int main(int argc, char* argv[])

{

   实现统计一个学员的成绩; //伪代码,详细代码请见上章相关部分

 

  do

   {

      //提问是否继续统计:  

      cout <<"是否开始新的统计?(Y/N)?";

      cin >> c;

     

     //如果用户输出的不是字母Y,说明他不想继续统计了,我们需要中断循环。

     if( c != 'y' && c != 'Y')

         break;

     }

     while (true);

}

 

请首先 while(true)部分,其条件直接写上真(true),表明这是一个无条件的循环(即,循环将无条地一直持续下去),这岂不犯了程序界的武林大岂:成了一个“死循环”?其实,相信你已明白,在循环体内,有一个break的分支在呢,当判断用户输入的字母既不是小写的y,也不是大写的Y,break就起它能起的作用了。

 

三个例子,都是从循环判断的条件摘出一部分或全部(最后一个例子),然后循环体中,采用一个if判断,结束break来跳出循环。可能你会问:为什么要break呢?直接用原来的方法,在while处判断条件不是很好吗?

 

break的长处在于,它可以在循环体内的任意位置进行判断。

继续上一例。假设我们出于慎重,想在用户按入 N 时,再问他一句是否真的退出统计,则此时显示出了break的方便:

int main(int argc, char* argv[])

{

   实现统计一个学员的成绩; //伪代码,详细代码请见上章相关部分

 

  do

   {

      //提问是否继续统计:  

      cout <<"是否开始新的统计?(Y/N)?";

      cin >> c;

 

      //如果用户输出的不是字母Y,说明他不想继续统计了,我们需要中断循环。

      if( c != 'y' && c != 'Y')

     {

          //出于慎重起见,我们要再问一句用户是否真的不统计了?

          cout << "您真的不想继续计算了?(Y:真的结束 / N:继续统计)";

          cin >> c;

          

          //这回,如果用户输入Y,表明他真的不统计了:

          if( c == 'Y' || c == 'y')

               break;

      }

     }

     while (true);

}

 

在上面例子,由于用户的两次输入我们都采用变量 c (char 类型)接收。但如果第一次输入 字母‘Y’时,循环需继续,但如果用户是在第二次输入‘Y',则表示是真的不统计了,循环却必须结束;所以,此时while无法仅凭c的值来做出正确判断,但,采用break,正如上面代码,我们在合适的位置安排一个break,从而直观地实现了。

 

当然,这里仅为了讲学方便而举此例,如果你真的在程序中为了一个“是否继续统计”而问了用户两遍,可能会被用户骂做“神经质”。不过,如果是删除某些重要数据(直接删除,不可恢复的情况),多问一次就选得很重要了。(比如句神英语删除用户操作就会在最后多问一句“真的要说再见吗?我们会想你的……”)

 

 

再举一例,看我们前面关于跑步的例子:

 

while(已跑的圈数 < 3 )

{

跑一圈……;

if(我身体感觉不妙)

     break;

}

 

这段代码有点问题,因为判断“我身体感觉不妙”是在跑完一圈之后……很可能我在某一圈刚开始跑时就觉得肚子剧痛,极可能是得阑尾炎啊!按照这段程序,我只有坚持跑完一圈后,才能break了……

要完美解决这个问题,我们将在本章再后讲到,现在先采用一个“通融”的办法,我们允许你每跑100米就检查一次吧:

 

while(已跑完图数 < 3)

{

跑第1个100米;

if(我身体感觉不妙)

     break;

 

跑第2个100米;

if(我身体感觉不妙)

     break;

 

跑第3个100米;

if(我身体感觉不妙)

     break;

 

跑第4个100米;

if(我身体感觉不妙)

     break;

}

代码中,我们将1圈拆为4个100米,每跑完1/4,我们就检查一次是否身体不对。看明白这个例子,我想你对break的用途和用法,可以算是理解了。

 

11.1.2 break 的一个“高级用法”

 

本小节不是很适于没有多少实际编程经历的初学者,所以初学者可以跳过,以后再回头阅读。当然,所谓的“高级用法”的确是应该加对引号的,所谈的内容只是一个高手们常用小小技巧。

使用do...break...while简化多级条件判断的结构。

 

如果你写过不少代码,那么一定会不时遇到类似下的情况:

假设要找到文件A,复制该文件为B;然后打开B文件,然后往B文件内写入一些内容;最后在写入成功后,我们需要再进行一些相关操作。

在此过程,遇到以下情况时将放弃后续的操作,认为是操作失败:

1、如果A文件不存在;

2、如果B文件已经存在,并且询问用户是否覆盖时,用户回答“不”;

3、无法复制出B文件;

4、无法打开B文件;

5、无法写入B文件;

6、无法正常关闭B文件。

 

用伪代码写该段程序为:

 

if( A文件存在 )

{

    执行A文件的相关操作;

    if( B文件不存在 || 用户允许覆盖原有B文件)

    {

        复制A文件为B文件;

        if(复制文件成功)

        {

            打开B文件;

       if(打开文件成功)

             {

                写入文件;

         if(写入成功)

         {

                    关闭B文件;

                    if(关闭成成功)

           {

                       执行其它必须在一切成功后进行的操作。

             ……  

                     }

                }

             }    

        }

    }

}

 

可能有些操作和判断可以同时处理,但这个程序的繁琐仍然不可避免,而现实中程序的复杂性往往要远过于此例。从语法上看,这个例子没有任何错误,但它的一层套一层的条件判断却让人难以书写,阅读,调试,在复杂的情况就容易造成人为的错误(比如最马虎的,花括号匹配不对等……)。

 

同样一段代码“程序老鸟”是这样写的:

 

do

{

   if(A文件不存在)

      break;

   执行A文件的相关操作;

  

   if(B文件存在 && 用户不允许覆盖)

      break;

   

   复制A文件为B文件;

   if(复制不成功)

      break;

 

   打开B文件;

   if(打开B文件不成功)

      break;

 

   写入文件;

   if(写入文件不成功)

      break;

 

   关闭B文件;

   if(关闭不成功)

      break;

 

    执行其它必须在一切成功后进行的操作。

  ……  

}

while(false);

 

看,代码是不是“直”了很多?这里用了do..while,可是根本不是为了循环,而是为了使用它的break功能。每当有操作不成功,就直接用break跳出循环。所以循环条件总是一个“永假” false。

在一个程序中,这种结构相当的多,为了更加一步淡化while的原来的循环用途,我们非常值得在代码加入两个共用的宏:

#define BEG_DOWHILE do {

#define END_DOWHILE } while(false);

 

这里举的是do...while结构,在某些情况下,可以使用while...来实现类似功能。

 

11.1.3 break 在for循环中的一点注意

 

前面举的例子都是do...while或while,break在for循环也一个样。请看下面例题:

 

例一:从1开始累加,每次递增1,请问累加到哪个数,累加和超过2000?请输出该数,及当时的累加和。

 

分析:和求1~100的累加和类似,只是在发现累加和已经超过2000时,就输出当前累加的数,然后结束循环。

 

for(int i=1,sum=0;;i++)

{

   sum += i;

   if(sum > 2000)

   {

       cout << i << "," << sum << endl;

       break;

   }

}

 

输出结果为:

 

63,2016

 

关于这段例子,需要注意三点:1、循环条件初始的位置,我们同时声明两个变量;2、没有循环条件。为了解这两点注意。

 

最后一点注意是关于break和“条件因子变化”的注意。我们知道,for每执行一遍循环体后,都将执行一次“条件因子变化”语句(见上图③)。现在需要注意的是:

在for循环中,执行break后,“条件因子变化”语句同样被跳过,没有被执行循环就被中断。

至此,break 在 while,do...while,for中的用法我们都已见过。不过,你还记得吗,我们最早学到break是在哪里?在讲条件分支语句中switch里。如果你有点忘了那里的break是起什么作用,现在就去看看吧。

 

11.1.4 多层循环中的break

 

break 只能跳出当前层的循环,所以,如果有多层循环,则在内层的break跳出循环后,外层的循环还将继续。

前面说跑步的例子,一圈400米,我们每跑100检查一下是否肚子疼什么的,如果疼得利害就break,不跑了。这和现实不符,我们应该每跑一步就检查一次是否肚子疼最合理。

一圈得分成几步呢?显然不能再像上面分成四次检查那样写代码了。我们加一层循环,也就是把跑一圈的工作用一个循环来实现:

 

while(一圈未结束)

{

跑一步;

}

 

然后,我们在每跑完一步时加入一个判断:

 

while(一圈未完)

{

跑一步;

  

if(我身体感觉不妙)

     break;

}

 

把这跑一圈的代码加入外层循环:

while(已跑完图数 < 3)

{

    while(一圈未完)

    {

       跑一步;

       if(我身体感觉不妙)

           break;

     }

}

外层的while用于负责一圈一圈循环跑完三圈,内层的while用于负责一步一步地循环跑完一圈,同时负责每跑一步就检查是否身体不妙,若身体不舒服,就跳出循环,不跑了。看起来代码很完美,其实BUG已经产生:问题就在那个break。当“我身体感觉不妙”后,程序遇上break,跳出内层while,落入外层的while,外层的循环可没有被break,所以程序将继续外层的循环。假如你跑第一圈跑了一半时肚子疼,按照这段程序逻辑,那好这第一圈剩下的一半你可以不用跑了,但后面的两圈你还得继续。

解决的第一种方法是:

while(已跑完图数 < 3)

{

    while(一圈未完)

    {

       跑一步;

       if(我身体感觉不妙)

           break;

     }

     if(我身体感觉不妙)

         break;

}

我们在外层也进行了一次判断,这样当然就可保证从内层跳出来以后,外层的循环也被跳出。但在内层已经做过一次“感觉”的情况下,外层还要重新“感觉”一次,这种代码让人不爽,所以我们可以加一个变量,用于记住现在的身体状态:

bool needBreak = false; //是否需要跳出循环

while(已跑完图数 < 3)

{

    while(一圈未完)

    {

       跑一步;

  

       if(我身体感觉不妙)

       {

          needBreak = true; //做一标志,需要break;

           break;

     }

     if(needBreak)

         break;

}

虽然本人的课程并不是绕什么圈子,可是在这有关break的长篇累牍的文字中,想必各位现在头脑里只有一个词,只有一个念头:break。想 break?后面的课程就不要啦?不可能,我们还是continue吧。

 

11.2 continue

 

continue 汉意为继续。它的作用及用法和break类似。重要区别在于,当前循环遇到break,是直接结束循环,而若遇上continue,则是停步当前这一遍循环,然后直接尝试下一遍循环。我把“尝试”加粗以引起注意,为什么要注意原因后面再说,请先看下面关于break和continue的对比:

 

break的作用与用法 - gxhy_lyf - 无名小卒博客

continue并不结束整个循环,而仅仅是中断的这一遍循环,然后跳到循环条件处,继续下一遍的循环。当然,如果跳到循环条件处,发现条件已不成立,那么循环也将结束,所以我们称为:尝试下一遍循环。

 

例二:求整数1~100的累加值,但要求跳过所有个位为3的数。

分析:在循环中加一个判断,如果是该数个位是3,就跳过该数不加。

 

如何判断一个1到100中,哪些整数的个位是3呢?还是 % ,将一个2位以内的正整数,除以10以后,余数是3,就说明这个数的个位为3。

比如: 23 ,除以10,商2,余数3。这里我们不需要商,所以用求余(也称为求模)运算:23 % 10 = 3。

int sum = 0;  

for(int i = 1; i<=100;i++)

{

   if( i % 10 == 3)

      continue;

   sum += i;

}

cout << sum << endl;

和break正相反:

在for循环中,执行continue后,“条件因子变化”语句没有被跳过,将被执行一次,然后再尝试循环的下一遍。

在上例中,当条件 i %10 ==3 成立时,continue 被执行,于是,程序首先执行 i++;然后执行 i <= 100 的判断。如果将该段程序改成while,正确答案为:

int sum = 0;

int i = 1;

while(i <= 100)

{

   if( i % 10 == 3)

   {

      i++;

      continue;

   }

   sum += i;

   i++;

}

cout << sum << endl;  

请注意程序中的两句"i++;",缺一不可。   

11.3 goto

臭名昭著的goto出场了。

goto的汉义为“转到”,在计算机语言里,它的完整名称为:“无条件跳转语句”。几乎所有高级语言都会劝你尽量不要使用它goto。因为它会破坏程序的模块性,严重降低一段程序的可读性。若是老外写的书,则比喻使用大量goto的代码:“像意大利面条”。嗯,其实北京的杂酱面也很缠绕……可惜没有走向世界。

goto的用法是,首先要在代码中某处加上一个位标(也称标号),然后在代码中的需处,加上goto,并写让要跳转到位标。比如你在第三行代码加一个位标:A : ,然后可以在第10行写上一个goto A,程序执行到该行时,就将跳到第三行。

加位标的方法是在一空行加上位标的名称,命名规则和变量一样,但最后要加上一冒号“:”。

例如:

int i = 1;

A :

cout << i << endl;

i++;

if(i <= 10)

goto A;

... ..

goto 虽然号称“无条件跳转”,事实上倒是有些条件限制。主要是三条。

1、goto只能在当前的同一程序段内跳转;

2、goto 可以从循环内跳转到循环外的代码,但不能从循环外的代码跳到循环内;

3、在有goto的跳转范围内,不能再使用C++允许的临时变量声明。

  好了,其实笔者写程序近10年,惟一用到goto的地方就是:将一段简单的程序故意用goto写得面目全非,以期能让破解程序的人因为眼晕而放弃功击……一句老话:如果没有什么特殊理由,不要在程序里使用goto。

原创粉丝点击