第十一章 流程控制拾遗与混合训练

11.1 break

   11.1.1 break的作用与用法

   11.1.2 break 的一个“高级用法”

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

   11.1.4 多层循环中的break

11.2 continue

11.3 goto

11.4 流程控制强化训练

   11.4.1 求绝对值

   11.4.2 判断用户输入字符的类型

   11.4.3 等腰三角形图形的输出

   11.4.4 输出正弦曲线图

   11.4.5 标准体重计算程序

 

说“拾遗”,可能你会以为本章的内容不是重点?那可不是,流程控制的内容并不多,却支撑着所有程序的框架!所所有有关流程的内容都是基础加重点。只是本章中继续讲到一些关键字可以改变流程,但并不独自构成完整流程结构。

另外,作为流程控制内容的结束章节,我们于最后安排了一些各流程混合使用的训练。

 

11.1 break

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后,“条件因子变化”语句同样被跳过,没有被执行循环就被中断。

(完整代码请见lz1.bpr)

 

至此,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的对比:

 

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;

 

(完整代码请见lz2.bpr)

 

和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。

 

11.4  流程控制强化训练

 

这一节将提供一系列的有关流程控制的实例,程序中知识点全部不超过你学到本章时的水平。有些程序需要一些数学上的小小技巧。

所有实例是从建立一个新的控制台工程开始。所以一些由CB自动生成代码我将不写出。你应该知道如何将它们写成一个完整的控制台程序。如果实在有困难也不要紧,各个实例的完整我都已经提供下载。(但只有付费报名学员可以通过课程下载器下载,解密)。

 

最后,在例子中会出现不少常见的编程技巧,可能在前面的课程中没有直接讲到,我会对这些技巧进行解说。

 

11.4.1 求绝对值

 

例三:用户输入一整数,请用程序输出绝对值

分析:

1、本例演示了一个最简单的流程控制:if...

2、同时你可以学到如何求一个数的绝对值,很简单;另外,看一个数是否为负数,就是看它是否小于0,这也很简单。

3、另外,本例使用一个 while(true)来无限循环,你可以不断地输入,如果要中止程序,请按Ctrl+C,这是由操作系统提供的,DOS窗口下中止程序的热键。(因此,本例也无须在最后加 getchar();这行代码)

 

答案:

#include <iostream.h>
 

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

{

    int num;

 

    while(true)

    {

        cout << "求绝对值的程序" << endl;

        cout << "要中止运行请按 Ctrl + C " << endl;

         

        cout << "==============" << endl;

        cout << "请输入一个整数:";

        cin  >>  num;

 

        //正数和0的绝对值是本身,负数的绝对值为其相反数

        if(num < 0)

           num = -num;

 

        cout << "绝对值为:" << num << endl << endl;  //输出两个换行,仅是为了美观

    }

}

 

11.4.2 判断用户输入字符的类型

 

例四:用户输入一字符,请判断该字符是:大写字母,小写字母,数字字符,其它字符。

分析:

1、本题主要演示多级 if..else...

2、在ASCII表中,题中所提的 前3类字符,其ASSCII值都各自连续(换句话说就是:所有的大写字母都是连续的,所有在小写字母也是连续的……)。基于这一点,你容易看明白代码中为判断字符类型的方法。

3、本解答也采用了循环,所以也不用加getchar()这行代码。关于循环中条件判断方法比较特殊,请见代码后的说明。

 

#include <iostream.h>

#include <conio.h>

 

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

{

    char ch;

    cout << "请输入一个字符:" << endl;

 

    while( (ch = getche()) != '\r' )

    {

         cout << endl; //加一个换行,仅为了输出美观

        

         if( ch >= 'A' && ch <= 'Z')

            cout << ch << "是一个大写字母。" << endl;

         else if ( ch >= 'a' && ch <= 'z')

            cout << ch << "是一个小写字母。" << endl;

         else if( ch >= '0' && ch <= '9')

            cout << ch << "是一个数字字符。"  << endl;

         else

            cout << ch << "是一个其它的字符。" << endl;

    }

 

这段代码中,我们用到了getche()库函数,它的声明包含在 conio.h 文件中,所以本例程除了"#include <iostream.h>"以外,还另需 "#include <conio.h>"。

 

getche() 和我们常用的 getchar()同样是接收用户从键盘输入的一个字符,但getchar()在用户输入字符后,用户还需要敲一下回车键才能完成输入;而getche()则在用户敲入一个字符后,立即完成。本例中,我们希望如果用户敲一个回车键,则程序自动结束(见下面解析),所以我们采用getche()函数。

 

现在来看while的循环条件:

 

while( (ch = getche()) != '\r' )

 

这行代码依次完成下面两件事: 

首先是: ch = getche() ,它等待用户敲入一字符,然后将该字符存储在ch变量。

然后是判断条件: (……) != '\r' 。 程序判断 ch 是否不等于 '\r', '\r' 即回车(return)字符。也就是看用户输入的字符是否为回车键,如果不是,则循环继续,如果是,则循环结束。

记住,在C和C++里 一个赋值表达式: A = B, 本身也有值,值就是完成赋值后的A。在上例中,A是ch,B是 getche()。在C,C++里,几乎所有表达式本身都有值,比如:1+2 的值是3;而表达式 a = 3 的值为3。

理解这段代码,最好的方式就是在CB中运行它。至于我们所要练习的多级if...else在例中的表现,我不再多说,你需要自已看懂它。

最后解释一下 conio.h, 其中 con 即我们总说的控制台,io则和iostream中的io一样,指:input/output。

 

11.4.3 等腰三角形图形的输出

 

例五:请输出以下图形:

      *

     ***

   *****

   *******

  *********

分析:

新手刚看这道词可能觉得无从下手,其实,如果把图形改成一个矩形:

 

  *********

  *********

  *********

  *********

  *********

那么就很好解决了:输出5行,其中每行都输出9个* 。

 

for(int i=0;i<5;i++)

{

  for(int j=0;j<9;j++)

  {

    cout << '*';

  }

}

 

对于三角形,程序仍然是这个结构:需要两层循环。同样是要输出5行,所以外层循环不变;不同的地方在于每一行输出的内容。其实三角形同样是输出一个矩形,只不过有些地方要打空格,有些地方要打*,以下我们用“-”表示空格,则三角形实为:

 

  ----*----

  ---***---

 --*****--

  -*******-

  *********

所以,问题的重点在于:在每一行中,哪些地方要输出空格,哪些地方要输出星号?如果我们行和列都从1开始编号,如图:

仔细观察我们发现,哪一列要打星,哪一列要打空格,主要和该列与第5列(红线所在列)的距离有关:

第 1 行: 只有第5列本身打星,第5列和第5列(自身)的距离是0

第 2 行: 除了第5列以外,增加第4、6列,4和6与5的距离都为1

第 3 行: 增加了3、7两列要打星,3,7两列和5的距离都为2

……

 

行了,规律就是:在第n行内,凡是和第5列的距离小于n的列,都要打星,其余的列打空格。

下面代码中,row表示当前行,col表示当前列。

 

答案:

 

#include <iostream.h>

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

{

   for(int row=1;row<=5;row++)

  {

      for(int col=1;col<=9;col++)

      {
            if( col-5 > -row && col-5 < row)
                cout << "*";
            else
                cout << " ";
        }

     cout << endl;
   }

  getchar();

  return 0;
  }

以下是输出结果:

 

在本例中,为了保持大家日常生活的习惯,我对行,列的编号均从1开始,其实,C,C++程序员更习惯于编程从0开始,即原来的第1行现在称为第0行,第1列称为第0列,则相关代码如下(黑体部分为改动处):

 

 for(int row=0;row<5;row++)

  {

      for(int col=0;col<9;col++)

      {
            if( col-4 >= -row && col-4 <= row)
                cout << "*";
            else
                cout << " ";
        }

     cout << endl;
   }

学会从0开始索引的思想方法,这也是大家所要注意的,否则在阅读别人代码时会比较困难。

 

11.4.4 输出正弦曲线图

 

例六:请在DOS窗口输出正弦曲线图

分析:

1、还记得初中代数学的正弦函数吧?

  y = sin (x);

  当x从0到2π变化时,y的值在 -1 和 +1 之间变化。

  我们现在的任务就是随着x(位置)的变化,在y的位置上打一个点即可。

2、C为我们提供了sin的库函数。只要我们给它x的值,它就能计算出相应的y值。sin(x)函数包含在头文件main.h里。

3、为了方便,我们将“竖”着输出曲线,即x的值由上而下增长,而y值则在左右“摇摆”。并且,如果y值为负数的话,那么将输出到屏幕的最左边外面,所以我们将y值统一加上一值,用于向右偏到合适的位置。至于要加多大的值,和第4点有关。

4、和前面输出“等腰三角形”类似。假如我们需要在屏幕的某一行最右边(行末)打出一个点,我们的方法是在前边连续地打满空格。正弦值在 -1到1之间,我们不可能打零点几个空格,所以,需要正弦值放大一定的倍数。

 

答案:

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

{

   #define PI 3.14159

   

   int scale = 30; //放大倍数

   double X,Y;

 

   for(float X = 0.0; X <= 2 * PI; X += 0.1)

   {

    // 乘上scale 是为了放大Y值,而加上scale则是为了向右边偏移

       // 以保证所有的点都不会跑出屏幕左边。

       Y = sin(X) * scale + scale;  

 

       //前面打空格

       for(int dx = 0;dx<Y;dx++)

            cout << ' ';

 

       cout << '.' << endl;

    }

 

   getchar();

 

   return 0;

}

 

完整的代码请查代码文件。由于输出画面太长,所以这里不显示结果图。

 

11.4.5 标准体重计算程序

 

尽管类似输出“九九口诀表”、“等腰三角形”,“正弦曲线”这些题目对锻练大家的编程思维颇为有益,但可能很多人都不会喜欢这种题。

嗯,这很多人当中,就有我自已一个。所以,我们来点有趣的题目吧。

街上有一种电子称,你站上去一量身高体重,它就会告诉你的身材是否为标准体重。可是有一天我兴冲冲地往上一站,那机器竟怪里怪气地说:“本仪器不适于非洲儿童……”。害得我当众狼狈而逃!

回去后,我痛下血本,每天大鱼大肉,如此月余,自认为横了一点,很想再测测这回该是哪一洲的儿童。然而由于上次的经历已经对我的造成了极大的心灵伤害,以致于我上街看见那种电子称就腿软。只好自购小站秤一台,米尺一条,不过,如何计算是否标准体重呢?嗯,就是这节课的“标准体重计算程序”了。

 

计算标准(理想)体重的方法是从网上搜到的:

 

“最近军事科学院还推出一种计算中国人理想体重的方法:

北方人理想体重=〔身高cm—150〕x0.6十50(kg)

南方人理想体重=〔身高cm—150〕x0.6十48(kg)”

 

(原文请见:三九健康网

 

考虑到女性一般要比男性轻,所以如果是女性,我们还需要将标准体重减去2公斤。

 

可见,要计算一个人的标准体重,必须知道是男人女人,是北方人还是南方人,及他的身高。

用户还必须输入他的现实体重,这样,在程序计算出标准体重之后,我们计算实际体重在标准体重百分之几的范围之内,作出不同判断。

 

代码请见例程文件,加有详细的注解。本题事实上没有什么复杂算法,所以比前面的题都要简单--尽管代码看上去长多了。

试用时请注意: 程序需要输入数字时,如果不小心输入字母并回车,将引起死循环,这是cin的问题所致,请按Ctrl + C 强行退出即可。

 

在课程的最后,测一下自已的体重与“理想体重”的差距,是个不错的选择……测好了?能告诉我程序对你的身材所作的评价吗?

[到页首]