预计阅读本页时间:-
使用条件运算符和if else结构可以很容易地编写从两个选择中进行选择的程序。然而,有时程序需要从多个选择中选择一个。可以利用if else if...else来这样做,但多数情况下,使用C的switch语句更加方便。程序清单7.11举例说明了switch语句是怎样工作的。该程序读入一个字符,然后相应地输出以该字符开头的动物名称。
程序清单7.11 animals.c程序
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
我们很懒散地只到f就停止了,但是后面可以依此类推。在进一步解释该程序之前,让我们看看一个运行示例:
本程序的两个主要特点是switch语句的使用和输入的处理。首先看看switch语句怎样工作。
7.7.1 使用switch语句
紧跟在单词switch后的圆括号里的表达式被求值。在这里,它就是刚刚输入给ch的值。然后程序扫描标签(label)列表(case'a':,case'b':,如此等等),直到搜索到一个与该值相匹配的标签。然后程序跳到那一行。要是没有相匹配的标签怎么办?如果有被标记为default:的标签行,程序就跳到该行;否则,程序继续处理跟在switch语句之后的语句。
break语句有什么作用呢?它导致程序脱离switch语句,跳到switch之后的下一条语句(请参见图7.5)。如果没有break语句,从相匹配的标签到switch末尾的每一条语句都将被处理。例如,如果把程序里面的break去掉,然后输入字母d来运行程序,会得到如下交互式结果:
图7.5 switch语句中有和没有break时的程序流程
从case'd':到switch结尾的所有语句都被执行了。
顺便提一下,break语句用于循环和switch中,而continue仅用于循环。但是,如果switch语句位于一个循环中,则可以把continue用于switch语句的一部分。在这种情况下,就像在其他的循环中一样,continue导致程序跳过该循环的其余部分,其中包括switch的其余部分。
如果您熟悉Pascal,就会发觉switch语句和Pascal的case语句很相似。最大的差别在于,如果仅希望处理某个带有标签的语句,switch语句要求使用break。另外,不能在C的case中使用一个范围。
圆括号中的switch判断表达式应该具有整数值(包括char类型)。case标签必须是整型(包括char)常量或者整数常量表达式(仅包含整数常量的表达式)。不能用变量作为case标签。因而,switch结构是这样的:
7.7.2 只读取一行的首字符
animals.c的另一个特点是它读取输入的方法。在运行示例中您可能已经注意到,当输入dab时,仅仅处理了第一个字符。这种特性在期望响应单字符的交互式程序中通常很合适。产生这种动作的是下面的代码:
这个循环从输入读取字符,直到出现由回车键产生的换行字符。注意,函数返回值没有被赋给ch,因此,字符仅被读取并丢弃。因为最后一个被丢弃的字符是换行符,所以下个读入的字符是下一行的首字符。在外层while循环中,由getchar()读取它并将其值赋给ch。
假设用户开始时按下了回车键,以致遇到的第一个字符是换行符。下面的代码处理这种可能:
7.7.3 多重标签
如程序清单7.12所示,可以对一个给定的语句使用多重case标签:
程序清单7.12 vowels.c程序
假定ch是字母i,则switch语句定位到标签为case'i':的位置。因为没有break同该标签相关联,所以程序流程继续前进到下一个语句,即i_ct++;。如果ch是I,程序流程就直接定位到那条语句。本质上,两个标签都指向相同的语句。
严格地讲,case'U'的break语句并不需要,因为即便没有这个break,程序还是会进行swith结构的下一个语句,也就是default情况下的break语句。因此,case'U'的break语句可以去掉以缩短代码。另一方面,如果后面还需要再添加其他的情况(例如,你可能需要把y计为元音),那么现在保留这个break可以防止你到时候忘了添加。
下面是一个运行示例:
在这个特例中,可以通过使用ctype.h系列(表7.2)中的toupper()函数在进行判断之前将所有的字母转换为大写字母来避免多重标签。
或者,如果希望保留ch的值不变化,可以这样使用该函数: