1. 语句结构
语法形式
switch语句从字面上讲,可以称为开关语句,当然理解上不要以为就只有开和关,可以想象它是一个多路开关。它是一种多分支结构。
switch语句的语法形式为:
switch(整型表达式)
{
case 常量表达式1:语句1
case 常量表达式2:语句2
//……
case 常量表达式n-1:语句n-1
default:语句n
}
解读整型表达式
switch后面的小括号是一个整型表达式,这与if不同。if条件表现的是相互对立的两种状态,而对于多分支结构的switch,是用多个整数值表现多种选择。if条件的对立性总是相对于0而言,所以只要某种数据类型的表达式能够表示0值,便可以充当if语句的条件,但是switch中的表达式的值需要对应到不同的处理入口,其相当于入口编号,所以限制以用整型数表示是明智的。
例如,下面的代码错误地用浮点类型作switch的表达式,因而会引起编译错误:
float f= 4.0;
switch (f) { //错误
//……
}
处理入口
“case常量表达式:”即处理入口(也称其为“标号”),常量表达式相当于入口编号,入口编号是不能重复的,所以每一个case的常量表达式的值必须互不相同。
例如,下面的代码是某个switch语句的局部,其case处理入口出现相同常量值,导致了编译错误:
case 'A' :cout<<"this is A\n";
case 'B' : cout<<"this is 65\n"; //错误,A等于ASCII码的65
处理入口编号不能重复,但可以颠倒。也就是说,入口编号的顺序不重要。各个case(包括default)的出现次序可任意。例如:
swtich(a)
{
case 3: b=1; break;
default: b=2; break; //正确
case 1: b=3; break;
}
default处理入口:如果switch后面的整型表达式不能匹配任何一个预定的处理入口,那么若有default处理入口,就转入该入口,否则就退出switch语句,什么也不做。
2. switch嵌套
switch语句可以嵌套,也就是在switch语句中的入口处理语句中又包含了switch语句。case与default标号是与包含它的最小的switch相联系的。例如:
int i,j;
//……
switch(i)
{
case 1 ://
case 2 :
switch(j)
{ //嵌套switch
case 1:
case 2:
default:
}
case 3:
}
switch(j)中的标号(入口编号)虽然与外面的switch(i)中的标号相同,但编译器不会混淆。
需要switch嵌套是基于switch中的入口语句可以是语句集合,而语句集合是可能需要开关语句作进一步编程处理的。
3. 用好break
全程顺序性
在if语句中,if与else属下各自描述的语句是彼此独立的。但是在switch语句中,每个case只是标定处理入口,各个入口的语句并不排他。因此,switch语句中的全部处理入口描述的语句构成了一个顺序执行的动作序列。例如,下列代码描述一个五级计分的程序:
switch(grade){
case 'A': cout<<"Excellent\n";
case 'B': cout<<"Very Good\n";
case 'C': cout<<"Good\n";
case 'D': cout<<"Satisfactory\n";
case 'E': cout<<"Minimally Acceptable\n";
default : cout<<"Error\n";
}
当变量grade取'D'值时,将输出:
Satisfactory
Minimally Acceptable
Error
而不是所想象的单一的Satisfactory字串。
break的排他性
为了让switch中处理入口的语句具有入口独立性,从而有更多的描述灵活性,语言中专为switch语句配备了break语句。在switch语句中遇上break便意味着终止switch语句的执行,这就自然地构成了各个入口语句的互斥。改写上述代码,在每个入口处理的最后填上break语句,便得到:
switch(grade){
case 'A': cout<<"Excellent\n";break;
case 'B': cout<<"Very Good\n";break;
case 'C': cout<<"Good\n";break;
case 'D': cout<<"Satisfactory\n";break;
case 'E': cout<<"Minimally Acceptable\n";break;
default : cout<<"Error\n";
}
这时候,当变量grade取'D'时,将只输出对应的成绩描述字串:
Satisfactory
switch语句中的最后一条语句的下一句便是出口了,面对的是switch语句终止后的下一条语句,所以就没有必要再用break特地退出了。
放弃使用的效果
break语句是在switch语句中人为添加的,而不是默认的,这就多了一些编程操作而显得“笨拙”。一些评论家一次而攻击switch语句“太土”。但正由于加不加是可选的,给switch一些编程的灵活性。例如,频繁输入一个整数n以决定输出n个相同字串“Hello.”便可以有一种用switch语句的更好选择:
//方法1
for (int n; cin>>n;)//反复输入整数n
{
for(int i=1; i<=n; i=i+1)//循环控制输出n个字串(1≤n≤3)
cout<<"Hello."
cout<<"\n";
}
//方法2
for(int n; cin>>n;)
{
switch(n){
case 3: cout<<"Hello."//都没有用break
case 2: cout<<"Hello."
case 1: cout<<"Hello."
}
cout<<"\n";
}
按这两种方法,则输入:
2 1 3 0 3
都能得到结果:
Hello.Hello.
Hello.
Hello.Hello.Hello.
Hello.Hello.Hello.
方法1在循环语句中嵌套使用了1~n的for循环语句,以决定输出语句执行的次数。不管怎么说,针对每次输入的整数,都要做n次条件判断。
方法2在循环语句中使用了开关语句,它通过直接转向执行,完成n次字串输出。
显然在上述代码中,循环控制结构所付出的代价相对多分支转向结构要大,若数据量很大,则会带来明显的性能差别。
由于n值很小,使用多分支语句时,通过安排处理的入口编号而使前后语句得到共享,语句简化且易懂。
选择使用的效果
break在switch语句中,对每个case分支都是可选的,也就是说,有些可以有,有些可以没有。因为有了这样的特性,编程变得更灵活。例如:
switch(ch){
case'-': b=-b;//无break
case'+': a=a+b;break;
case'*': a=a*b;break;
case'/': a=a/b;
}
首先要明白,在C++中,并不是只有整型数才可以做加减的。代码中a、b实体如果是大对象,做负号操作可能远比减法操作的代价小,减法操作可能比加法操作还要耗费精力,或者根本没有该数据类型的减法操作。因此,做减法不如预先做反向操作,再做加法划算。
break注解
break是一个关键字,该关键字独立构成一条语句,其功能是在switch、for、while、do-while语句中,跳出结构而转向执行吓一条语句。或者说break语句强行终止上述语句的执行。对于if语句,其if-else结构中的语句块本身就是排他性的,所以没有必要用break去干预。