7章 分支结构程序设计

在本书前面各章的程序中,所有程序都是按语句在源代码中的排列顺序执行的,写在前面的语句先执行,写在后面的语句后执行。在实际程序设计中,程序不会只采用这种执行方式。在很多情况下,需要根据用户输入的值(或中间运算结果)决定执行程序的一部分语句,而跳过另一部分语句。这样的程序结构称为分支结构。C 语言提供了 if 语句和switch语句来完成这样的功能,它们可根据条件判断的结果,选择所要执行的程序语句。

7.1 分支程序流程

程序设计一般有三种结构:

顺序结构;

分支结构;

循环结构(循环结构将在下一章中介绍)。

顺序结构的程序设计是最简单的(本书前面各章的程序都是这种结构)。设计顺序结构的程序时,只要按顺序写出相应的语句即可,它的执行顺序总是自上而下,依次执行。这是后两种程序结构的基础。大多数情况下,顺序结构都是作为程序的一部分,与分支结构或循环结构一起构成一个复杂的程序。

顺序结构的程序能完成赋值、计算、输入、输出等功能,但不能根据输入值或计算结果选择执行一部分程序语句。如果程序中需要根据输入值或计算结果选择部分语句执行,就要使用分支结构。分支结构的执行是依据一定的条件选择执行路径,而不是按照语句出现的物理顺序执行。

设计分支程序的关键在于选择合适的分支条件,根据不同的分支条件选择适当的语句执行。分支结构程序可以嵌套,有时程序的结构很复杂,设计这类程序时,一般都要先绘制程序流程图,然后根据程序流程写出源程序,这样做把程序设计分析与语言分开,使得问题简单化,易于理解。程序流程图是根据解题分析所绘制的程序执行流程图。一般的分支结构程序流程图如图7-1所示。

图7-1 分支程序流程

在图7-1所示流程图中,“表达式”可为C语言的各种表达式,程序计算表达式的值,根据“表达式”的值选择执行的语句,如果表达式的值为true(非0值),则执行“语句或语句块1”,跳过“语句或语句块2”;如果表达式的值为false(0值),则执行“语句或语句块2”,跳过“语句或语句块1”。

其中的两个分支可为单独的语句,也可以是语句块。如果是语句块,应该使用大括号将其括起来。

7.2 if语句

C语言中最常用的分支语句就是if语句,它根据给定的表达式的值进行判断,以决定执行某个分支程序段。

7.2.1 基本if语句

if语句的基本格式如下:

          if(表达式) 语句;

以上语句的意思是:如果表达式的值为真(非0),则执行其后的语句,否则,不执行该语句。程序流程图如图7-2所示。

图7-2 if语句流程

if关键字之后的表达式通常是逻辑表达式或关系表达式,但也可以是其他表达式,如赋值表达式等,甚至也可以是一个变量。例如,以下两行语句都可在C语言中使用:

          if (i=1)  语句;
          if (i)  语句;

第1行语句中表达式的值永远为非0(赋值表达式将1赋给变量i,表达式返回的值也就是1),所以其后的语句必定要执行。

第2行语句中,如果变量i的值不为0,则执行其后的语句。

以下语句:

        if (i=j)  printf("%d",i);

将变量j的值赋给变量i,如果变量j不为0,则表达式的值为非0,将执行其后的printf语句;若变量j的值为0,则表达式的值为0,将不执行printf语句。

在if语句中,表达式即使为一个变量,也必须用括号括起来。有了括号作分隔符,if关键字与括号之间可以使用空格分隔,也可不输入空格分隔。表达式与后面的语句之间的分隔与此类似。例如,以下两行语句都是正确的。

        if(max<j)max=j;
        if (max<j) max=j;

以上两种书写方法都没有语法错误,建议读者使用后一种方式,使程序的格式更规范。

还可以按以下格式书写:

        if (max<j)
            max=j;

前面曾介绍过,C语言中,以分号为语句结束标志,以上语句虽然写在两行中,但只有一个分号,仍然是一条语句。如果写成以下形式(在表达式后面跟一个分号):

        if (max<j) ;
            max=j;

当表达式的值为真时,将执行一个空语句,而不是执行下一行的语句。以上代码中,无论max是否小于j,都要执行第2行的语句。初学者需要理解以上代码的含义。

编写程序接收用户输入两个整数,求两数中的最大数。

【程序7-1】用if语句求最大数

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int i,j,max;
        6:
        7:      printf("请输入两个整数:");
        8:      scanf("%d%d",&i,&j);
        9
        10:     max=i;
        11:     if (max<j) max=j;
        12:     printf("您输入的数是%d和%d,最大数是%d\n",i,j,max);
        13:     getch();
        14:     return 0;
        15: }

编译执行以上程序,输入两个整数后得到如图7-3所示的结果。

图7-3 【程序7-1】执行结果

在以上程序中,使用变量max保存最大值。

第10行程序将用户输入的一个整数保存到变量max中。

第11行程序使用if语句比较变量max和变量j的值,如果变量j的值比变量max的值大,说明变量max保存的不是最大值,将变量j的值赋值给max。

第12行程序输出最大值max。

在【程序 7-1】中,if 语句表达式后面是一个语句。在更多的情况下,当表达式值为true时,需要执行多个语句,这时,需要使用语句块。其书写方式如下:

          if(表达式)
          {
            语句1;
            语句2;
            … …
            语句n;
          }
          语句m

当“表达式”的值为true时,执行大括号中的语句块,然后执行“语句m”及其后的语句。当“表达式”的值为 false 时,不执行语句块,直接执行语句块后面的“语句 m”及其后的语句。

注意

语句块中,大括号后面不能添加分号。

例如,改写【程序7-2】,将用户输入的两个整数按从小到大的顺序输出。

【程序7-2】用if语句对两个数排序

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int i,j,temp;
        6:
        7:      printf("请输入两个整数:");
        8:      scanf("%d%d",&i,&j);
        9
        10:     if(i>j)
        11:     {
        12:        temp=i;
        13:        i=j;
        14:        j=temp;
        15:     }
        16:     printf("您输入的数按从小到大顺序为%d,%d\n",i,j);
        17:     getch();
        18:     return 0;
        19: }

编译执行以上程序,按提示输入两个整数,得到如图7-4所示的结果。

图7-4 【程序7-2】执行结果

在第16行程序中,假设变量i的值比变量j的值小。要得到这种结果,就需要使用if语句进行判断,第10行程序进行判断。如果i的值大于j的值,则需要将变量i和变量j的值进行交换。在程序中,经常要用到交换两个变量值的情况,一般引用一个临时变量。如本例中,临时变量temp先保存变量i的值(此时,变量temp和i的值相同),再将另一个变量j保存到变量i中(此时,变量i和j的值相同,原来变量i中的值不存在了),最后将temp中的值保存到变量j中,完成了变量i和j的值交换。完成数据交换需要3个语句,因此,需要使用语句块(第12行至第14行为一个语句块)。

7.2.2 if else语句

上面介绍的if语句在表达式为true时,执行其后的语句或语句块,然后执行后面的语句;若表达式的值为false,则跳过其后的语句或语句块,直接执行后面的语句。在更多的时候,针对表达式为 true 或为 false 的情况,需要分别执行不同的语句,然后再执行后续代码。这时,可使用if … else语句,其语法格式如下:

        if (表达式) 语句1;
        else 语句2;

以上语句的意思是:如果表达式的值为true,则执行语句1,否则,执行语句2。程序流程图如图7-5所示。

图7-5 if else语句流程

其中的“语句1”和“语句2”也可以为语句块。

通过if else语句,可更方便地对条件进行处理。例如,使用if else语句修改【程序7-2】,完成相同功能,可使程序代码更简单。

【程序7-3】用if else语句对两个数排序

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int i,j;
        6:
        7:      printf("请输入两个整数:");
        8:      scanf("%d%d",&i,&j);
        9:
        10:     if(i>j)
        11:        printf("您输入的数按从小到大顺序为%d,%d\n",j,i);
        12:     else
        13:        printf("您输入的数按从小到大顺序为%d,%d\n",i,j);
        14:     getch();
        15:     return 0;
        16: }

以上程序中,第10行判断i和j的关系,如果i大于j,执行第11行代码,先输出j,再输出i(得到从小到大的顺序)。如是第10行程序判断i小于j,执行第13行程序,先输出i,再输出j。

以上程序执行可能有两种顺序,按语句序号排列分别为:

第一种执行顺序:1~10,11,12,14,15,16;

第二种执行顺序:1~10,12,13,14,15,16。

从上面列出的执行顺序可看出,第11行和第13行程序始终只能有一行被执行,而另一行被跳过,这就是分支结构的作用。

7.2.3 再论条件表达式

第5章中介绍了条件运算符和条件表达式,使用条件表达式可完成简单的分支任务。如使用条件表达式,可将【程序7-3】中的第7行至第10行程序改写为以下程序:

        printf("您输入的数按从小到大顺序为%d,%d\n",((i<j)?i:j),((i<j)?j:i));

在printf函数中,使用:

        ((i<j)?i:j)

得到两个变量i和j中较小的值,使用:

        ((i<j)?j:i)

使用条件表达式,可将程序源代码修改得更短,但其结构却不好体现。因此,建议读者在程序中,尽量少用条件表达式。编写程序时,首先应保证程序的易读性,而使用条件表达式体现不出这种特点。

7.3 嵌套if语句

使用if else语句可以处理两种分支的情况,如果有多个分支要处理,就需要使用if语句的嵌套格式了。

7.3.1 嵌套if语句的形式

所谓嵌套,就是在if语句后面的执行语句中,又包含if语句。if语句嵌套的一般形式可表示如下:

        if (表达式1)
          if (表达式2) 语句1;
        else
          if (表达式3) 语句2;

更复杂的情况下,在嵌套内的语句又是if else语句,其结构如下所示:

        if (表达式1)
          if (表达式2) 语句1;
          else 语句2;
        else
          if (表达式3) 语句3;
          else 语句4;

当然,以上结构中“语句1”~“语句4”还可以是if语句。

以上的结构中,每个if关键字都有一个else关键字对应,但是,如果是以下代码:

        if (表达式1)
          if (表达式2) 语句1;
        else 语句2;

在以上代码中,有2个if关键字,1个else关键字。这个else与哪个if配对呢?按代码书写缩进的方式看,是准备将else与第1个if配对。即“表达式1”的值为true时,再判断“表达式2”的值;若“表达式1”的值为false,则执行“语句2”,其流程图如图7-6所示。

图7-6 if嵌套流程图1

但是,事与愿违。按上面格式书写的代码并不会按图7-6所示流程执行。C语言规定, else总是与它前面最近的,且没有else对应的if配对,因此,上述代码的实际流程应该如图7-7所示。

图7-7 if嵌套流程图2

为了让程序按图7-6所示流程执行,可以在代码中添加大括号,构造语句块,来确定if和else配对关系。例如,将上面的代码改为如下形式:

        if (表达式1)
        {
          if (表达式2) 语句1;
        }
        else 语句2;

这样,当“表达式1”的值为true时,执行大括号内的语句块;当“表达式1”的值为false时,执行else后面的“语句2”。

7.3.2 if语句嵌套实例

在需要复杂逻辑判断的程序中,往往需要使用嵌套的if语句来实现程序。在编写代码之前,最好先使用流程图将各种判断理清,再使用C语言编写代码。这样可减少程序中if语句嵌套的错误。

下面用两个实例演示if语句的嵌套。

第一个例子检查用户输入的字符是大写字母、小写字母、数字或其他符号。对用户输入的字符,有4种可能,可通过对输入字符的ASCII码进行判断,确定输入字符属于哪种类型,各字符类型对应的ASCII码范围如下(参见附录A中的ASCII码表):

大写字母:65~90;

小写字母:97~122;

数字:48~57;

特殊符号:其他。

程序流程图如图7-8所示。

图7-8 【程序7-4】流程图

根据图7-8所示流程图,编写具体的程序如下:

【程序7-4】检查输入字符类型示例(if语句嵌套)

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      char c;
        6:
        7:      printf("请输入一个字符:");
        8:      scanf("%c",&c);
        9:
        10:     if (c>=65 && c<=90)
        11:        printf("您输入的是大写字母!\n");
        12:     else
        13:        if (c>=97 && c<=122)
        14:            printf("您输入的是小写字母!\n");
        15:        else
        16:            if (c>=48 && c<=57)
        17:               printf("您输入的是数字!\n");
        18:            else
        19:               printf("您输入的是特殊符号!\n");
        20:     getch();
        21:     return 0;
        22: }

编译执行以上程序,随机从键盘上输入一个符号,程序可显示该字符的类型。

在以上程序中,因为每一个if关键字都有一个else与之匹配,所以在代码中没有使用大括号来限制匹配。

另外,以上程序在书写嵌套if语句时,采用了缩进方式,使程序中各层次之间的关系很明了。

接下来看一个更复杂的例子。要求用户输入3个整数,使用if嵌套的方式,对这3个整数进行排序(不允许使用临时变量交换数据),按从大到小的顺序输出。

首先分析一下,本例程序不允许使用临时变量交换数据,只能改在printf函数中改变各变量的输出位置,使输出结果按从大到小的顺序排列。用户输入3个数,共有6种组合,按数据的大、中、小排列,分别如下:

大、中、小

大、小、中

中、小、大

中、大、小

小、中、大

小、大、中

假设输入三个整数,分别保存在三个变量a、b、c中,使用if嵌套分别判断两个变量的大小,得到以上的6种组合。程序流程图如图7-9所示。

图7-9 【程序7-5】流程图

根据如图7-9所示的流程,编写代码如下:

【程序7-5】三个数排序示例(if语句嵌套方法)

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int a,b,c;
        6:
        7:      printf("请输入三个整数:");
        8:      scanf("%d%d%d",&a,&b,&c);
        9:
        10:     if (a>b)
        11:        if (b>c)
        12:           printf("%d,%d,%d\n",a,b,c);
        13:        else
        14:            if (a>c)
        15:               printf("%d,%d,%d\n",a,c,b);
        16:            else
        17:               printf("%d,%d,%d\n",c,a,b);
        18:     else
        19:        if (b<c)
        20:            printf("%d,%d,%d\n",c,b,a);
        21:        else
        22:            if (a>c)
        23:               printf("%d,%d,%d\n",b,a,c);
        24:            else
        25:               printf("%d,%d,%d\n",b,c,a);
        26:     getch();
        27:     return 0;
        28: }

编译执行以上程序,输入前面介绍的6种数据组合,可看到最后都可输出从大到小排列的3个数据。

以上程序主要是为了演示if嵌套语句而编写。在实际的程序中,使用一个临时变量对数据进行交换,可很简单地完成以上程序的功能。将以上程序按图7-10所示的流程图改写,具体代码如下。

图7-10 【程序7-6】流程图

【程序7-6】三个数排序示例(交换方法)

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int a,b,c,temp;
        6:
        7:      printf("请输入三个整数:");
        8:      scanf("%d%d%d",&a,&b,&c);
        9:
        10:     if (a<b)
        11:     {
        12:        temp=a;
        13:        a=b;
        14:        b=temp;
        15:     }
        16:     if (a<c)
        17:     {
        18:        temp=a;
        19:        a=c;
        20:        c=temp;
        21:     }
        22:     if (b<c)
        23:     {
        24:        temp=b;
        25:        b=c;
        26:        c=temp;
        27:      }
        28:      printf("%d,%d,%d\n",a,b,c);
        29:      getch();
        30:      return 0;
        31: }

以上程序中,假设3个变量a、b、c按顺序保存着从大到小的值。第10行程序判断a若小于b,则不满足假设条件,需使用第12~14行程序,将a、b变量的值进行交换,使a中的值较大。接着在第16行程序中判断a若小于c,则于第18~20行程序中,将a、c变量的值交换,使a中的值为最大值。第22行程序比较b和c的值,若b小于c,则于第24~26行程序,将b、c变量的值交换,使b中的值大于等于c。最后在第28行程序中使用printf函数输出a、b、c三个变量的值,即可得到从大到小的顺序。

提示

以上程序中,也可将每个语句块中的3个交换数据的语句写在一行中。

对比【程序7-5】和【程序7-6】可以看出,后一个程序使用的语句数量与【程序7-5】相比,并没有少许多,但通过引用临时变量,使程序的逻辑结构变简单了,很容易弄明白。因此,在遇到需要使用复杂的if嵌套语句时,应该考虑是否有更简单的方法,因为嵌套层次过多,很容易把逻辑关系搞混乱。

7.4 if eIse if语句

在7.3节中,使用if嵌套的方式进行多个条件的组合。但嵌套层次太多的话,代码中很容易出错。对于多个分支的情况,可以使用if else if语句。

7.4.1 if else if语句格式

使用前面介绍的if语句,主要用于处理两个分支的情况。使用其嵌套形式,也可以处理多分支。C语言中专门提供了处理分支选择的if语句(另外还有个swith语句也可处理多分支,在7.5节介绍),其语法格式如下:

        if (表达式1)
          语句1;
        else if (表达式2)
          语句2;
          ... ...
        else if (表达式m)
          语句m;
        else
          语句n;

其执行过程是,从上到下依次判断各表达式的值,当某个表达式的值为true 时,则执行其对应的语句。然后跳到整个if语句之外,继续执行程序。如果所有的表达式的值均为false,则执行“语句 n”。然后继续执行后续语句。流程图如图7-11所示。

图7-11 if else if流程图

在以上结构中,“语句1”~“语句n”又可以是if语句,从而构成if语句的嵌套。如果省略最后的else关键字,有可能在该if结构中,不执行任何语句(所有表达式的值都不为true),而直接执行后续语句。

注意

else if之间有一个空格,连写为elseif是错误的。

7.4.2 if else if实例

使用if else if改写【程序7-4】,可使用程序看起来更简单,也更易懂,具体代码如下:

【程序7-7】检查输入字符类型示例(if else if语句)

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      char c;
        6:
        7:      printf("请输入一个字符:");
        8:      scanf("%c",&c);
        9:
        10:     if (c>=65 && c<=90)
        11:        printf("您输入的是大写字母!\n");
        12:     else if (c>=97 && c<=122)
        13:        printf("您输入的是小写字母!\n");
        14:     else if (c>=48 && c<=57)
        15:        printf("您输入的是数字!\n");
        16:     else
        17:        printf("您输入的是特殊符号!\n");
        18:     getch();
        19:     return 0;
        20: }

编译执行以上程序,将得到与【程序7-4】同样的结果。但该程序比【程序7-4】的结构简单得多。

7.5 多路分支——switch

一般的if语句只有两个分支可供选择,而实际工作中常常需要用到多分支的选择。使用if else if也可处理多分支的情况,但多数情况下,使用switch语句处理多路分支将更加方便。

7.5.1 switch语句格式

使用switch,可方便地处理同一表达式多分支的情况,其语法格式如下:

        switch (表达式)
        {
        case常量表达式1:
          语句1;
          break;
        case常量表达式2:
          语句2;
          break;
            ... ...
        case常量表达式m:
          语句m;
          break;
        default :
          语句n;
        }

其执行过程为:首先计算表达式的值,然后将该值与后面的各个case关键字的常量表达式值相比较,当表达式的值与某个常量表达式的值相等时,即执行其后的语句;然后不再进行判断,继续执行后面所有case后的语句,直到遇到break语句,退出switch语句。如表达式的值与所有case 后的常量表达式都不等,则执行default后的语句。其流程图如图7-12所示。

图7-12 switch流程图

switch语句主要应用在根据同一个表达式的值进行多分支的情况下。使用时需要注意以下事项:

switch关键字后面括号内的表达式的值必须为整型,不能为实型数。

每个case关键字的常量表达式后面要添加冒号(:)。

case关键字后面可以是常量(如1、2等),也可以是常量表达式(如1+2、3+3等),但表达式中不能有变量(如1+i是错误的)。因为case关键字后面的值,必须在编译阶段被确定。

每个case后的常量表达式的值要与switch后面括号内的表达式的类型一致,且各个case后的常量表达式必须互不相同,否则,会出现执行两路分支的矛盾。

执行完一个case后面的语句后,流程控制转移到下一个case继续执行。“case 常量表达式”只是起语句标号作用,并不是在该处进行条件判断,因此,如果在执行完当前case语句后,需要跳到switch语句后执行,就需要在该case分支的最后加上一条break语句。

default 分支可以省略,如果省略该分支,当所有常量表达式与 switch 后表达式的值不相等时,switch结构中将没有语句被执行。

7.5.2 switch实例

与单词的字面意思相似,switch像一个多路开关,按下哪个开关,将接通哪个流程,执行对应的代码。下面以实例演示switch语句的具体用法。

例如,要求编写一个程序,将用户输入的一个整数转换为对应的中文星期名称。

【程序7-8】整数转换为中文星期名称(switch语句)

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int w;
        6:
        7:      printf("请输入1个整数:");
        8:      scanf("%d",&w);
        9:
        10:     switch(w)
        11:     {
        12:     case 0:
        13:         printf("星期日\n");
        14:         break;
        15:     case 1:
        16:         printf("星期一\n");
        17:          break;
        18:     case 2:
        19:         printf("星期二\n");
        20:         break;
        21:     case 3:
        22:         printf("星期三\n");
        23:         break;
        24:     case 4:
        25:         printf("星期四\n");
        26:         break;
        27:     case 5:
        28:         printf("星期五\n");
        29:         break;
        30:     case 6:
        31:         printf("星期六\n");
        32:         break;
        33:     default:
        34:         printf("输入错误!\n");
        35:     }
        36:     getch();
        37:     return 0;
        38: }

编译执行以上程序,在提示信息中,输入一个整数5,将显示中文星期名称“星期五”,结果如图7-13所示。

图7-13 【程序7-8】执行结果

提示

在学习了本书后面介绍的函数内容后,可将该程序改写为一个函数,用于星期名称的转换。

从以上程序中可以看出,与if语句不同,在case后面,虽然有多个执行语句,但可以不用大括号将这些语句括起来组成语句块,程序会自动顺序执行本case语句后面所有的执行语句(当然使用语句块也是正确的)。这是因为,在switch结构中,每个case相当于一个标号,标号后可以有多个语句,程序会顺序执行这些语句,直到遇到break语句,才跳出switch结构。对于switch结构中的最后一个分支(如本例中的default),可以不加break语句。执行最后一个分支后,按顺序本来就应该执行switch结构后面的一个语句。当然,在最后一个分支中,加上break语句也是正确的。

7.5.3 使用多重标号

在switch结构中,每个case关键字和后面的常量表达式构成一个标号。一般情况下, switch选择一个标号的语句进行执行,在下一个标号之前添加break语句,跳出switch结构,使得各分支得以分别执行。如果在下一个标号之前(当前标号的语句序列结束时)没有添加break语句,会是什么情况呢?

将【程序7-8】中第14、17、20、23、26、29、32这几行的break语句删除,得到如下程序。

【程序7-9】switch语句多重标号示例(错误结果)

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int w;
        6:
        7:      printf("请输入1个整数:");
        8:      scanf("%d",&w);
        9:
        10:     switch(w)
        11:     {
        12:     case 0:
        13:         printf("星期日\n");
        14:     case 1:
        15:         printf("星期一\n");
        16:     case 2:
        17:         printf("星期二\n");
        18:     case 3:
        19:         printf("星期三\n");
        20:     case 4:
        21:         printf("星期四\n");
        22:     case 5:
        23:         printf("星期五\n");
        24:     case 6:
        25:         printf("星期六\n");
        26:     default:
        27:         printf("输入错误!\n");
        28:     }
        29:     getch();
        30:     return 0;
        31: }

编译执行程序,输入整数1,将得到如图7-14左图所示的结果。再次执行该程序,输入整数5,将得到右图所示结果。

图7-14 【程序7-9】执行结果

在执行以上程序时,当在第8行程序中输入1时,第10行程序中switch语句计算表达式w的值为1,将直接跳到第14行程序,从case 1标号后的语句开始执行,因为一直没遇到break语句,程序将从第15行顺序执行,所以得到如图7-14左图所示的输入结果(将第15行以后的每个printf输出语句都执行了)。

同理,在执行以上程序时,输入5时,将直接跳到第22行程序,从case 5标号后的语句开始执行。

像本例程序这样,不使用break语句跳出switch结构,使得程序将执行多个标号后的语句,在大多数情况下,都会使程序的结果出现问题。但是,利用switch的这一特性,也可设计出让多个case共用一组执行语句的代码。

例如,某物流公司准备搞一次优惠活动,对用户发送的货物运费进行返利。根据用户运费金额不同,返利标准也不同,返利标准如下(F为运费):

F<100,返10%;

F<200,返8%;

F<500,返7%;

F<1000,返6%;

F≥1000,返5%。

现在要求用户输入金额,计算出用户实际应交付的运费,即扣除返利后的金额。

根据对上述数据的分析,返利的变化是有一定规律的,每个返利变化点都是100的整数倍。因此,可要求用户输入运费后,将运费与100整除,即可得到一个0~10(或更大)的值,使用switch分别设置不同值对应的返点比率即可。具体代码如下:

【程序7-10】分档计算运费(switch语句)

        1:  #include <stdio.h>
        2:
        3:  int main()
        4:  {
        5:      int f;
        6:      float d,a;
        7:
        8:      printf("请输入运费金额:");
        9:      scanf("%d",&f);
        10:
        11:     switch(f/100)
        12:     {
        13:     case 0:
        14:         d=0.1;
        15:         break;
        16:     case 1:
        17:         d=0.08;
        18:         break;
        19:     case 2:
        20:     case 3:
        21:     case 4:
        22:         d=0.07;
        23:         break;
        24:     case 5:
        25:     case 6:
        26:     case 7:
        27:     case 8:
        28:     case 9:
        29:         d=0.06;
        30:         break;
        31:     default:
        32:        d=0.05;
        33:     }
        34:     a=f*(1.0-d);
        35:     printf("实际支付运费金额为:%.2f\n",a);
        36:     getch();
        37:     return 0;
        38: }

第5行声明整型变量f,用来保存总运费。第6行的实型变量d为返利标准,变量a保存实际支付金额。

第11行程序中,将int变量与100整除,得到的是一个整数。若输入333,将得到3,输入98,将得到0。

第13~15行程序将在输入的金额小于100时执行(f/100时等于0),执行到第15行的break后将跳出switch结构,执行第34行的程序。

第16~18行程序将在输入的金额大于等于100,且小于200时执行(f/100等于1),执行到第18行的break后将跳出switch结构,执行第34行的程序。

第19~23行程序将在输入的金额大于等于200,且小于500时执行。当f/100等于2时,跳转到第19行,该行标号下没有可执行语句,顺序执行第20~23行,到第23行的break后将跳出switch结构,执行第34行的程序。当f/100等于3时,跳转到第20行,该行标号下没有可执行语句,顺序执行第21~23行,到第23行的break后将跳出switch结构,执行第34行的程序。当f/100等于4时,跳转到第21行,执行后面的第22~23行,到第23行的break后将跳出switch结构,执行第34行的程序。

同样,第24~30行程序也采用类似方式执行。

若用户输入的值f与100整除后的结果超过了9,跳至第31行执行。

第34行程序根据前面设置的返利标准(保存在变量d中),计算出实际应支付金额,在第35行中使用printf函数输出。

编译执行以上程序,输入一个金额333,将得到如图7-15所示的结果。

图7-15 【程序7-10】执行结果

7.5.4 switch和if比较

通过本章前面的学习,知道了使用if语句和switch语句都可实现程序的分支。那么,在什么情况下使用if语句,在什么情况下使用switch语句?本章最后对这两个语句进行一下比较。

1.switch的优点

switch结构的优点:

没有复杂的逻辑判断,程序结构简单。

对于分支很多的情况,特别适用switch结构。

与if结构相比,switch程序执行效率高。

2.switch的缺点

switch的缺点如下:

在C语言中,对switch语句是有一定限制的,只能是基于一个整型值进行分支选择,如果分支是基于一个实数型变量或表达式的值,就不能使用switch语句。

switch只能测试是否相等,对于要求测试条件在某个期间的情况(使用关系或逻辑表达式),只能使用if语句。

如果变量必须落入某个很大的范围,也不能很方便地使用switch。例如,有以下语句:

          if (i>1 && i<10000)

要将以上条件改写为switch结构,需要编写2~9999中每个整数的case标号。

3.if的优点

if结构的主要优点有:

使用if结构,可实现很复杂的逻辑判断。

使用switch结构实现的分支,都可通过if结构实现,而不能使用switch结构实现的分支,只有使用if结构来实现。

对于分支较少的情况,使用if结构更简单。

4.if的缺点

if结构的缺点也是显而易见的,主要有以下缺点:

分支较多的情况下,程序结构复杂,容易出错。

if的嵌套层次过深,也容易使程序变得很复杂。

与switch相比,执行效率要低一些。

以上列出了switch和if的优缺点,在大多数情况下,尽量使用switch编写代码,使程序简洁,执行效率更好。对于一些switch不能完成的复杂逻辑判断,才使用if。当然,对于简单的分支(如两分支),直接使用if即可。