购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.3 分支结构

大家还记得在第2章所学习的C语言的运算符吧?其中对于除法运算符来讲,它有一个要求:除数不能为0。而我们的例3-1竟然没有考虑这一情况,假如用户不小心(或者是故意)把10输入成了0,程序会怎样呢?

程序得到一个令人费解的结果“1.#J”(表示无穷大的意思)。为了让程序更健壮一些,我们是不是应该在程序中对用户所输入的除数进行检查呢?一旦发现除数为0,就不应该让它再进行除法的运算,从而避免出现这样一个令人费解的结果。这就需要用到C语言中的分支结构了。C语言的分支结构可以控制程序的部分流程是否被执行,或是从多条执行路径中选择一条来执行。

3.3.1 if语句

if语句可以通过对特定条件的判断,来决定某条语句是否被执行。它的使用格式为:

小括号内的表达式即为判断的条件,当表达式的值为真时,执行语句;当表达式的值为假时,不执行语句。其中的语句可以是单条语句,也可以是复合语句,其执行流程如图3.1所示。

图3.1 if语句执行流程

现在就可以通过if语句来对除数为0的情况进行检查,只有除数不为0时,才会进行除法运算。修改部分的代码如下:

在得到用户输入的两个整数后,我们对变量b的值进行检查。将变量b放入if语句的小括号内,若变量b的值为0,则为假,就不会执行后面的语句;若变量b的值不为0,则为真,就会执行后面的语句。这样的话,当用户输入整数后,程序若发现除数为0时,就不会进行除法运算,也不会通过printf函数打印输出最终结果了。

这里需要注意的一点是:我们把原先的两条语句通过大括号组成了一条复合语句,也就是这条复合语句中的语句要么都执行,要么都不执行。如果没有这个大括号,意思就完全不同了。如:

由于没有大括号,if语句只会包含“res = (float)a / b;”这一条语句,下面的printf函数调用语句就不再属于if语句了。这会导致不管变量b的值是真是假,printf函数调用语句都会被执行。

最后再说明一下,我们也可以在if语句的条件表达式里写成“b != 0”,即使用“if(b != 0)”的方式,它同样是判断变量b的值是否不等于0。而使用“if(b)”的方式会让代码显得更加简练,它们的作用实质是一样的。

3.3.2 if…else语句

现在这个程序能对除数为0的情况进行检查了,但是还不够好,因为当除数为0时,没有任何的结果输出,对于程序不太了解的人会产生疑问。更好的设计应该是当除数不为0时,程序打印输出正常的结果,除数为0时,打印一条信息明确告之用户。

if…else语句和if语句相比,多了else部分,其实就是多了一条执行路径,形成了二选一的流程执行情形。就好像我们走到了一个分岔口,是该往左走还是往右走呢?

if…else语句的使用格式如下:

当表达式的值为真时,执行if后面的语句1;当表达式的值为假时,执行else后面的语句2。对于语句1和语句2来说,无论何种情况,其中之一肯定会被执行,但它们两个永远不会同时被执行。其执行流程如图3.2所示。

图3.2 if…else语句执行流程

利用if…else语句可以很好地解决我们前面提到的问题,关键部分代码如下:

我们将原先代码中的if语句部分改用if…else语句,其中if部分的代码和之前没有变化,而在else部分使用了printf函数调用语句来打印除数不能为0的提示信息。下面显示了当除数为0时,程序的运行结果:

这里需要再强调一下,由于else部分只有一条语句,所以这里没有使用复合语句。不过并非不可以使用复合语句,像下面这样也是可以的:

即用一对大括号把printf函数调用语句括起来,这样就构成了复合语句,虽然这个复合语句中只有一条语句。也就是说,对于只有一条语句的情况,既可以采用单条语句的形式(不使用大括号),也可以采用复合语句的形式(使用大括号),推荐使用大括号,这样对代码的后续增加和维护都更方便。

3.3.3 if…else语句嵌套

通过if…else语句可以实现二选一的流程执行情况,那么通过对if…else语句的嵌套使用,就可以让程序实现出多选一的流程执行情形。下面就用一个经典的“评分案例”来演示。

例3-2 】要求由用户输入一个0~100的整数,以表示学生的考试分数,程序能够根据这个分数评定出相应的等级,共有A、B、C、D四个等级,其中90分及以上为优秀(用大写字母A表示),80~89分为良好(用大写字母B表示),60~79分为及格(用大写字母C表示),60分以下为不及格(用大写字母D表示)。

代码如下:

在这个代码里,出现了3层的if…else语句嵌套,即在第一层if…else语句的else部分嵌套了第二层的if…else语句,在第二层的else部分又嵌套了第三层的if…else语句,如图3.3所示。

图3.3 if…else语句的三层嵌套

当程序运行时,首先会执行第一层if…else语句,判断其表达式的值,若为真则执行if部分的语句(打印输出A),若为假则执行else部分,即执行第二层的if…else语句;接着判断第二层表达式的值,若为真则执行if部分(打印输出B),若为假则执行else部分,即第三层的if…else语句;最后判断第三层表达式的值,若为真则执行if部分(打印输出C),若为假则执行else部分(打印输出D)。

例如我们在程序运行时,输入整数70(即整型变量score的值为70)。则程序的执行流程为:

① 判断出第一层表达式“score >= 90”的值为假,执行其else部分;

② 判断出第二层表达式“score >= 80”的值为假,执行其else部分;

③ 判断出第三层表达式“score >= 60”的值为真,执行其if部分;

④ 打印输出结果C,程序执行完毕。

实际执行的情况如下:

3.3.4 if…else if…else语句

在C语言中允许将if语句或if…else语句看成是一个整体,把它们当作一条语句来处理。也就是说,我们可以把第一层if…else语句中的else部分(即第二层if…else语句)看成是一条语句;同理,把第二层if…else语句中的else部分(即第三层if…else语句)也看成是一条语句。那么现在就可以省去代码里的大括号,并把else关键字往上提一行,紧跟在上一层else的后面,这样就形成了if…else if…else语句。修改之后的相关代码如下:

使用if…else if…else语句,是不是让程序的逻辑结构变得更加清晰啦?它的执行流程和使用if…else语句嵌套的执行流程一样,完全可以认为if…else if…else语句就是对if…else语句嵌套的一种变形写法。

这里需要注意的一点是“else if”中的两个关键字之间,有一个空格字符。即这两个关键字不能连在一起,要用空白字符进行分隔,若写成“elseif”,就会产生编译时期的语法错误了。

3.3.5 switch…case语句

C语言的分支结构中还有一个switch…case语句,通过它同样能实现多选一的效果,而且使代码的逻辑更加清晰。switch…case语句的使用格式如下:

switch关键字后面的小括号内是一个整型表达式,下面的大括号内有着一系列的case标签和一个可选的default标签。每个case标签由“case”关键字打头,后面跟着一个整型常量表达式(不可使用变量或实型常量),并以冒号“:”结束。其中每个case标签中的整型常量表达式的值必须唯一,不可重复。default标签不需要表达式,直接用“default”关键字加上一个冒号“:”即可。在每个case标签和default标签之后,可以有相应的语句,以及一个break。switch…case语句的执行流程如图3.4所示。

程序运行时,首先会计算整型表达式的值,然后用该值与后面的所有case标签进行一一匹配(即查看该值与case标签的表达式的值是否相等)。如果有匹配的case标签,则从该case标签起,执行后续的语句,直至遇到break语句或右大括号时为止;若没有匹配的case标签,则从default标签起,执行后续的语句,直至遇到break或右大括号时止;若没有匹配的case标签,则执行default标签,若没有default标签,则该switch…case语句什么都不做。

图3.4 switch…case语句执行流程

现在知道break语句的作用了吧,它可以终止switch…case语句的执行。如果在某处漏掉了必要的break,则switch…case语句不会被终止,程序会继续执行后面的语句,直到遇见break语句或者代表整个switch…case语句结束的右大括号。

下面用switch…case语句重写一下之前的“评分案例”,代码如下:

在代码中,switch…case语句的整型表达式为“score / 10”,通过这个表达式,我们就可以得到一个分数对10进行整除的结果。例如分数为75,则得到一个值为7的结果。这样做的目的,就是把原来0~100的分数,换算到一个0~10的范围,如果直接使用分数,就需要对应101个case标签,而使用分数段,最多也就需要对应11个case标签了。其中的“case 10:”对应100分,“case 9:”对应90~99分,…,“case 6:”对应60~69分,“default:”对应0~59分,明白了吧!

代码中把“case 10:”和“case 9:”放在了一起,即对应着90~100分的“优秀等级”,如果出现这个区间的分数,就会被这两个标签之一所匹配,然后通过printf函数打印出“Grade:A”;“case 8:”对应着80~89分,如果被匹配,就会打印“Grade:B”;同样的,“case 7:”和“case 6:”放在了一起,对应着60~79分,如果被匹配,就会打印“Grade:C”;而低于60分的情况,没有被任何的case标签所匹配,即在switch…case语句中没有找到“case 5:、case 4: case 3:、case 2:、case 1:、case 0:”这些case标签,所以最终就会匹配“default:”,打印出“Grade:D”。

例如我们在程序运行时,输入数字65,则在switch…case语句中会匹配到“case 6:”,从而在控制台窗口上打印出“Grade:C”。实际运行情况如下:

最后补充说明一点,在switch…case语句中,并没有规定default标签必须放在所有case标签之后,也就是default标签可以放置在任何位置,甚至可以出现在所有case标签之前,所以default标签下的break语句不要随意省略。 msPTPfNG7Xe8Us5lJmDn0QqoNaeQAakmnD5rsjM77e90zFnhEVGf44CPxyQybFWb

点击中间区域
呼出菜单
上一章
目录
下一章
×