c控制语句:分支和跳转

目录

1 if语句

2 if else语句

2.1 介绍getchar()和putchar()

2.2  多重选择else    if

2.3   else与if配对

2.4   多层嵌套的if语句

3    逻辑运算符

3.1  优先级

3.2    求值顺序

3.3     范围

4  一个统计单词的程序

5     条件运算符: ?:

6  循环辅助:continue 和  break

6.1  continue语句

6.2   break语句

7   多重选择:switch 和 break

 7.1  switch语句

7.2  只读每行的首字符

7.3  多重标签   ​

7.4  switch 和  if    else

8    goto语句

9       编程练习


1 if语句

while循环的测试条件利用scanf()的返回值来结束循环,因为scanf()在读到非数字字符时会返回0。if语句被称为分支语句选择语句,因为它相当于一个交叉点,程序需要在两条分支中选择一个执行。if语句的通用形式如下:

if(expression)

statement

2 if else语句

c还提供了if else形式,可以在两条语句之间作选择。if else语句的通用形式:

if(expression)

statement1

else

statement2

如果expression为真(非00,则执行statement1;如果expression为假或0,则执行else后面的statement2.statement1和statement2可以是一条简单语句或复合语句。c并不要求一定要缩进,但这是标准风格。缩进让根据测试条件的求值结果来判断执行哪部分语句一目了然。 如果要在if和else之间执行多条语句,必须用花括号把这些语句括起来称为一个快。

2.1 介绍getchar()和putchar()

     getchar()函数不带任何参数,它从输入队列中返回下一个字符。例如,下面的语句读取下一个字符输入,并把该字符赋值给变量ch;

      ch  = getchar(); 

      该语句与下面的语句效果相同:

       scanf("%c",&ch);

      putchar()函数打印它的参数。例如,下面的语句把之前赋给ch的值作为字符打印出来:

       putchar(ch);

      该语句与下面的语句效果相同:

       printf("%c",ch);

       由于这些函数只处理字符,所以它们比更通用的scanf()和printf()函数更快,更简洁。这两个函数通常定义在stdio.h头文件中(而且,它们通常是预处理宏,而不是真正的函数)。

       可以将while里面的测试条件换成下面这行代码:

       while( (ch = getchar() )   != '\n');

2.2  多重选择else    if

      下面是某电力公司的电费清单,单位是千瓦时(kwh):

       首   360kwh:         $0.13230/kwh

       续   108kwh:            $0.15040/kwh

       续    252kwh:         $0.30025/kwh

       超过  720kwh:        $0.34025/kwh

       符号常量表示不同的费率和费率分界点,以便把常量统一放在一处。这样,电力公司在更改费率以及费率分界点时,更新数据非常方便。该程序由一个if  else语句组成,else  部分包含另一个 if  else语句,该 if else 语句的else部分又包含另一个if  else语句。

2.3   else与if配对

        如果没有花括号,else与离它最近的if匹配,除非最近的if被花括号起来。

2.4   多层嵌套的if语句

        把嵌套if应用在下面的程序中。给定一个整数,显示所有能整除它的约数。如果没有约数,则报告该数是一个素数。

         为方便起见,程序应该使用一个循环让用户能连续输入待测试的数。这样,测试一个新的数字时不必每次都要重新运行程序。伪代码如下:

         提示用户输入数字

         当scanf()返回值为1

                   分析该数并报告结果

                    提示用户继续输入

        测试条件中使用scanf(),把读取数字和判断测试条件确定是否结束循环合并在一起。

        如何找出约数。最直接的方法如下:

        for( div = 2; div < num; div ++)

               if(   num % div == 0)

                         printf(“%d  is divisible by %d \n”,num,div);

        该循环检查2-num之间的所有数字,测试它们是否能被num整除。但是,这个方法有点浪费时间。如果144%2得0,说明2是144的约数:如果144除以2得72,那么72也是144的一个约数。所以,num % div 测试成功说明可以获得两个约数。144的成对约数:2和72,3和48,4和36,6和24,8和18,9和16,12和12,16和9,18和8,等等。在得到12和12这对约数后,又开始得到已找到得相同约数。因此,不用循环到143,在达到12以后就可以停止循环。

       测试的数只要到num的平方根就可以了,不用到num。我们不用在程序中计算平方根,可以这样编写测试条件:

        for(div = 2;(div * div) <= num; div++)

              if(num % div == 0)

                      printf("%d is divisible by %d  and %d.\n",num,div,num /  div);

       如果num是144,当div = 12时停止循环。如果num是145,当div  = 13 时停止循环。

       如果待测的数是一个完全平方数怎么办?报告144可以被12和12整除显得有点傻。可以使用嵌套if语句测试div是否等于num/div。如果是,程序只打印一个约数:

        for(div = 2; (div *div)    <= num; div ++)

        {

                     if( num % div == 0)

                     {

                                     if(div * div != num)

                                      {

                                                printf("%d  is divisible by %d and %d.\n",num,div,num/div);

                                       }

                                       else

                                        {

                                                printf("%d  is divisible by %d.\n",num,div);

                                         }

                     }

        }

         如何知道一个数字是素数?如果num是素数,程序流不会进入if语句。要解决这个问题,可以在外层循环把一个变量设置为某个值(如,1),然后在if语句中把该变量重新设置为0。循环完成后,检查该变量是否是1,如果是,说明没有进入if语句,那么该数就是素数。这样的变量通常称为标记

         一直以来,c都习惯用int作为标记的类型,其实新增的_Bool类型更适合。另外,如果在程序中包含了stdbool.h头文件,便可用bool代替_Bool类型,用true和false分别代替1和0。

        该程序在for循环的测试表达式中使用了逗号运算符,这样每次输入新值时都可以把isPrime设置为true。

        该程序会把1认为是素数,其实它不是。 

3    逻辑运算符

       if语句和while语句通常使用关系表达式作为测试条件。有时,把多个关系表达式组合起来会很有用,这个时候就可以使用逻辑运算符。下面的程序,计算输入的一行句子中除单引号和双引号以外其他字符的数量。

       程序首先读入一个字符,并检查它是否是一个句点,因为句点标志一个句子的结束。接下来,if语句的测试条件中使用了逻辑与运算符&&。该if语句翻译成文字是“如果待测试的字符不是双引号,并且它也不是单引号,那么charcount递增1。

      逻辑运算符两侧的条件必须都为真,整个表达式才为真。逻辑运算符的优先级比关系运算符低,所以不必在子表达式两侧加圆括号。

3种逻辑运算符
逻辑运算符含义
&&与                   
||

      假设exp1和exp2是两个简单的关系表达式,那么:

      1.当且仅当exp1和exp2都为真时,exp1  && exp2 才为真;

      2.如果exp1或exp2为真,则exp1  || exp2 为真;

      3.如果exp1为假,则  !exp为真;如果exp1为真,则!exp1为假。

3.1  优先级

       !运算符的优先级很高,比乘法运算符还高,与递增运算符的优先级相同,只比圆括号的优先级低。&&运算符的优先级比 | |运算符高,但是两者的优先级都比关系运算符低,比赋值运算符高。因此,表达式 a > b    &&  b >  c  ||  b >d 相当于  (a > b) && (b >  c) || (b  >  d)。

3.2    求值顺序

       除了两个运算符共享一个运算对象的情况外,c通常不保证先对复杂表达式中哪部分求值。例如,下面的语句,可能先对表达式 5  +  3求值,也可能先对表达式 9  +  6求值:

        apples  = (5+3) * (9+6);

        但是逻辑运算符是个例外,c保证逻辑表达式的求值顺序是从左往右。&&和| |运算符都是序列点,所以程序在从一个运算对象执行到下一个运算对象之前,所有的副作用都会生效。而且,c保证一旦发现某个元素让整个表达式无效,便立即停止求值。

        逻辑运算符的运算对象通常是关系表达式。!运算符只需要一个运算对象,其他两个逻辑运算符都需要两个运算对象,左侧一个,右侧一个。

3.3     范围

       &&运算符可用于测试范围。例如,要测试score是否90到100的范围内,可以这样写:

       if (range >= 90 && range <= 100)

          printf("good");

       下面这种写法有语义上的错误,而不是语法错误:

        if( 90 <=  range <=100)

           printf("good");

        由于<=运算符的求值顺序是从左往右,所以编译器把测试表达式解释为:

         (90 <=  range) <= 100

         子表达式 90 <= range 的值要么是 1,要么是0 。这两个值都小于100,所以不管range的值是多少,整个表达式都恒为真。因此,在范围测试中要使用&&。

4  一个统计单词的程序

        该程序要逐个字符读取输入,知道何时停止读取。然后,该程序能识别并计算这些内容:字符,行数和单词。

       要查找一个单词里面是否有某个字符,可以在程序读入单词的首字符时把一个标记(名为inword)设置为1。也可以在此时递增单词计数。然后,只要inword为1,后续的非空白字符都不记为单词的开始。下一个空白字符,必须重置标记为0(或false),然后程序就准备好读取下一个单词。以下是伪代码:

        如果c不是空白字符,且inword为假

                  设置inword为真,并给单词计数

         如果c是空白字符,且inword为真

                  设置inword为假

 

        !inword 与 inword == false 等价。

5     条件运算符: ?:

         c提供条件表达式作为if    else语句的一种便捷方式,该表达式使用?:条件运算符。该运算符分为两部分,需要3个运算对象。条件运算符是c语言中唯一的三元运算符。

          条件表达式的通用形式如下:

          expression1  ? expression2  :   expression3

          如果expression1 为真,那么整个条件表达式的值与expression2的值相同:如果expression1为假,那么整个条件表达式的值与expression3的值相同。

          条件运算符完成的任务用if   else语句也可以完成。但是,使用条件运算符的代码更简洁,而且编译器可以生成更紧凑的代码。如下程序计算给定平方英尺的面积需要多少罐油漆。

        该程序使用的变量都是int类型,除法的计算结果(sq_feet / COVERAGE)会被截断。也就是说,351/350得1。所以,cans被截断成整数部分。如果sq_feet % COVERAGE 得 0,说明sq_feet被COVERAGE整除,cans的值不变;否则,肯定有余数,就要给cans加1。这👉下面的语句完成:

cans += ( sq_feet  %   COVERAGE == 0) ? 0 : 1;

6  循环辅助:continue 和  break

       一般而言,程序进入循环后,在下一次循环测试之前会执行完循环体中的所有语句。continue和break语句可以根据循环体中的测试结果来忽略一部分循环内容,甚至结束循环。

6.1  continue语句

         3种循环都可以使用continue语句。执行到该语句时,会跳过本次迭代的剩余部分,并开始下一轮迭代。如果continue语句在嵌套循环内,则只会影响包含该语句的内层循环。

       while循环读取输入,直至用户输入非数值数据。循环中的if语句筛选除无效的分数。假设输入188,程序会报告:188 is an invalid value。在本例中,continue语句让程序跳过处理有效输入部分的代码。程序开始下一轮循环,准备读取下一个输入值。

        有两种方法可以避免使用continue,一是省略continue,把剩余部分放在一个else块中:

        if( score < 0 || socre > 100)

                   /*printf()语句*/

        else

        {      /*语句*/

         }

       另一种方法是,用以下格式来代替:

       if( socre >= 0  &&  score <= 100)

       { 

               /*语句*/

       }

         这种情况下,使用continue的好处是减少主语句组中的一级缩进。当语句很长或嵌套较多时,紧凑简洁的格式提高了代码的可读性。

        continue还可用作占位符。例如,下面的循环读取并丢弃输入的数据,直至读到行末尾:

         while( getchar() != '\n')

         ;

         当程序已经读取一行中的某些内容,要跳至下一行开始处时,这种用法很方便。问题是,一般很难注意到一个单独的分号。如果使用continue,可读性会更高:

         while( getchar() != '\n')

          continue ;

          continue语句让程序跳过循环体的余下部分。那么,从何处开始继续循环?对于while和do  while循环,执行continue语句后的下一个行为是对循环的测试表达式求值。如下代码:

          count = 0;

          while( count < 10)

         {  

                   ch = getchar();

                    if ( ch == '\n')

                             continue;

                             putchar(ch);

                             count ++;

          }

         该循环读取10个字符(除换行符外,因为当ch是换行符时,程序会跳过count++;语句)并重新显示它们,其中不包括换行符。执行continue后,下一个被求值的表达式是循环测试条件。

         对于for循环,执行continue后的下一个行为是对更新表达式求值,然后是对循环测试表达式求值。例如,考虑下面的循环:

         for( count = 0; count < 10; count++)

        {

                     ch = getchar();

                      if( ch == '\n')

                           continue;

                           putchar(ch);

        }

        该例中,执行完continue后,首先递增count,然后将递增后的值和10作比较。因此,该循环与上面while循环的例子稍有不同。while循环的例子中,除了换行符,其余字符都显示;而本例中,换行符也计算在内,所以读取的10个字符中包含换行符。

6.2   break语句

         程序执行到循环中的break语句时,会终止包含它的循环,并继续执行下一阶段。

      可以这样控制循环:

      while(scanf("%f %f",&length,&width) == 2)

       但是,用break可以方便显示用户输入的值。

7   多重选择:switch 和 break

       

 7.1  switch语句

          要对紧跟在关键字switch后圆括号中的表达式求值。在上面的程序当中,该表达式是刚输入给ch的值。然后程序扫描标签列表,知道发现一个匹配的值为止。然后程序跳转至那一行。如果没有匹配的标签怎么办?如果有default:标签行,就跳转至改行;否则,程序继续执行在switch后面的语句。

           break语句在其中起什么作用?它让程序离开switch语句,跳至switch语句后面的下一条语句。如果没有break语句,就会从匹配标签开始执行到switch末尾。

          break语句可用于循环和switch语句中,但是continue只能用于循环中。另外,c语言的case一般都指定一个值,不能使用一个范围。

           switch在圆括号中的测试表达式的值应该是一个整数值(包括char类型)。case标签必须是整数类型(包括char类型)的常量或整型常量表达式(即,表达式中只包含整型常量)。不能用变量作为case标签。switch的构造如下:

7.2  只读每行的首字符

          在上面的程序当中,当输入dab时,只处理了第1个字符。这种丢弃一行中其他字符的行为,经常出现在响应单字符的交互程序中。可以用下面的代码实现这样的行为:

          while(  getchar() != '\n')

                     continue;

         循环从输入中读取字符,包括按下enter键产生的换行符。注意,函数的返回值并没有赋给ch,以上代码所做的只是读取并丢弃字符。由于最后丢弃的字符是换行符,所以下一个被读取的字符是下一行的首字母。在外层的while循环中,getchar()读取首字母并赋给ch。

         假设用户一开始就按下enter键,那么程序读到的首个字符就是换行符。下面的代码处理这种情况:

         if(ch  == '\n')

            continue;

7.3  多重标签   

         假设如果ch是字母i,switch语句会定位到标签为case 'i':的位置。由于该标签没有关联break语句,所以程序流直接执行下一条语句,即i_ct ++;。如果ch是字母I,程序流会直接定位到case 'I' :。本质上,两个标签都指的是相同的语句。

7.4  switch 和  if    else

        何时使用switch?何时使用if    else?你经常会别无选择。如果是根据浮点类型的变量或表达式来选择,就无法使用switch。如果根据变量在某范围内决定程序流的去向,使用switch就很麻烦,这种情况用if就很方便:

         if( integer  < 1000  &&  integer > 2)

        使用switch要涵盖以上范围,需要为每个整数(3 - 999)设置标签。但是,如果使用switch,程序通常运行快一些,生成的代码少一些。

8    goto语句

          goto语句有两部分:goto 和标签名。标签的命名遵循变量名规则,如下所示:

           goto  part2;

          要让这条语句正常工作,函数还必须包含另一条标为part2的语句,该语句以标签名后紧跟一个冒号开始:

           part2 :   printf("Refined analysis:\n");

9       编程练习

1.编写一个程序输入,读到#字符停止。程序报告读取的空格数,换行符数和所有其他字符的数量。

使用while循环从输入队列中读取字符,测试条件为  (ch = getchar()) != '#'。定义三个计数器来计算空格数,换行符数和其他字符数。根据ch的值,使用嵌套if  else来递增不同的计算器。

2.编写一个程序读取输入,读到#字符停止。程序要打印每个输入的字符以及对应的ASII码(十进制)。每行打印8个“字符-ASCII码”组合。建议:使用字符计数和求模运算符(%)在每8个循环周期时打印一个换行符 。

使用while循环从输入队列中读取字符,测试条件为 (ch = getchar())  != '#' 。定义一个字符计算器,对字符计数器求模,当为8的倍数是打印一个换行符。同时如果是读取到换行符,可以使用continue跳过本次迭代的剩余部分,直接进入下一次迭代。

3.编写一个程序,读取整数直到用户输入0。输入结束后,程序应报告用户输入的偶数(不包括0)个数,这些偶数的平均值,输入的奇数个数及其奇数的平均值。

 4.使用if  else语句编写一个程序读取输入,读到#停止。用感叹号替换句号,用两个感叹号替换原来的感叹号,最后报告进行了多少次替换。

使用while循环读取用户的输入,测试条件为  (ch = getchar())!= '#'  。定义两个计数器,然后对ch的值判断。如果ch的值为 '.' 就递增 第一个计算器,并打印'!' ; 如果ch的值为 '!' 就递增第二个计数器,并打印两个 !! ; 如果以上两种情况都不会,直接打印ch的值。

5.使用switch重写练习4

6.编写程序读取输入,读到#停止,报告ei出现的次数。

 注意:该程序要记录前一个字符和当前字符。用"receive your eieio award"这样的输入来测试

从输入队列中循环读取数据,如果当前读取的值是e,就继续读取并判断下一值是否为i。最后打印ei出现的次数

7.编写一个程序,提示用户输入一周工作的小时数,然后打印工资总额,税金和净收入。做如下假设:

a:基本工资  = 10.00美元/小时

b:加班(超过40小时) = 1.5倍的时间

c:税率:    前300美元为15%

                    续150美元为20%

                    余下的为25%

用#define定义符号常量。不用在意是否复合当前的税法。

 

 8.修改练习7的假设a,让程序可以给出一个供选择的工资等级菜单。使用switch完成工资等级选择。运行程序后,显示的菜单应该类似这样:

**************************************************************************

enter  the number corresponding to the desired pay rate or action:

1)  $8.75/hr                             2)$9.33/hr

3)  $10.00/hr                           4)$11.20/hr

5)  quit

**************************************************************************

如果选择1-4其中一个数字,程序应该询问用户工作的小时数。程序要通过循环运行,除非用户输入5。如果输入1~5以外的数字,程序应提醒用户输入正确的选项,然后再重复显示菜单提示用户输入。使用#define创建符号常量表示各工资等级和税率。

打印选择菜单 - -循环获取用户输入的值(测试条件为 (scanf("%d",&input))   )-- 对用户输入的值进行判断:

1)如果值是1到4,提示用户输入工作小时数 

2)如果值是1-5提示以外的数,提醒用户输入正确的选项 

3)如果是值是5,退出循环

9.编写一个程序,只接收正整数输入,然后显示所有小于或等于该数的素数。

 提示用户输入数字

     当scanf()的返回值为1时

      分析该数并报告结果

      提示用户继续输入

判断是否是素数可以使用以下方法:

for( div =2,标记num为素数 ; (div *div)< =num; div++)

            if( num % div == 0)

              {

                            if(  (div * div) != num)

                           {

                             打印div为约数,num/div也为约数

                            }

                            else

                           {

                               打印div为约数

                           }

                         重置标记为不是素数

              }
            if(判断标记的值)

            {       打印num为素数

            }

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值