switch语句

来源:互联网 发布:php 支付宝接口 编辑:程序博客网 时间:2024/05/17 23:19

深层嵌套的if-else语句往往在语法上是正确的,但逻辑上却没有正确地反映程序员的意图.例如,错误的else-if匹配很容易被忽略.添加新的条件和逻辑关系,或者对语句做其他修改,都很难保证正确.switch语句提供了一种更方便的方法来实现深层嵌套的if/else逻辑.

假设要统计五个元音在文本里分别出现的次数,程序逻辑结构如下:

1.按顺序读入每个字符直到读入完成为止.

2.把每个字符与元音字符集做比较

3.如果该字符与某个原因匹配,则该元音的计数器加1.

4.显示结果.

使用此程序分析本章的英文版,得到以下输出结果:

Number of vowel a:3499
Number of vowel e:7132
Number of vowel i:3577
Number of vowel o:3530
Number of vowel u:1185

6.6.1  使用switch

直接使用switch语句解决上述问题:

char ch;
//initialize counters for each vowel
int aCnt=0,eCnt=0,iCnt=0,oCnt=0,uCnt=0;
while(cin>>ch){
 //if ch is a vowel,increment the appropriate counter
 switch(ch){
 case 'a':
  ++aCnt;
  break;
 case 'e':
  ++eCnt;
  break;
 case 'i':
  ++iCnt;
  break;
 case 'o':
  ++oCnt;
  break;
 case 'u':
  ++uCnt;
  break;
 }
}
//print results
cout<<"Number of vowel a:/t"<<aCnt<<'/n'
    <<"Number of vowel e:/t"<<eCnt<<'/n'
 <<"Number of vowel i:/t"<<iCnt<<'/n'
 <<"Number of vowel o:/t"<<oCnt<<'/n'
 <<"Number of vowel u:/t"<<uCnt<<endl;

通过对圆括号内表达式的值与其后列出的关键字做比较,实现switch语句的功能.表达式必须产生一个整数结果,其值与每个case的值比较.关键字case和它所关联的值称为case标号(case label).每个case标号的值都必须是一个常量表达式.除此之外,还有一个特殊的case标号-----default标号,以后介绍.

如果表达式与其中一个case标号的值匹配,则程序将从该标号后面的第一个语句开始依次执行各个语句,知道switch结束或遇到break语句为止.如果没有发现匹配的case标号(并且也没有default标号),则程序从switch语句后面的第一条语句继续执行.在这个程序中,switch语句是while循环体中唯一的语句,于是,switch语句匹配失败后,将控制流返回给while循环条件.

简单地说,break语句中断当前的控制流.对于switch的应用,break语句将控制跳出switch,继续执行switch语句后面的第一个语句.在这个例子中,正如大家所知道的,将会把控制转移到switch后面的下一语句,即交回给while.

6.6.2  switch中的控制流

了解case标号的执行流是必要的.

--------------------------------------------------------------我是华丽的分割线---------------------------------------------

注解:存在一个普遍的误解,以为程序只会执行匹配的case标号相关联的语句.实际上,程序从该点开始执行,并跨越case边界继续执行其他语句,直到switch结束或遇到break语句为止.

--------------------------------------------------------------我是华丽的分割线---------------------------------------------

有时候,这种行为的确是正确的.程序员也许希望执行完某个特定标号的代码后,接着执行后续标号关联的语句,但更常见的是,我们只需要执行某个特定标号对应的代码.为了避免继续执行其后续case标号的内容,程序员必须利用break语句清楚地告诉编译器停止执行switch中的语句.大多数情况下,在下一个case标号之前的最后一条语句是break.例如,下面统计元音出现次数的switch语句是不正确的:

//warning:deliberately incorrect!
switch(ch){
case 'a':
 ++aCnt;  //oops:should bave a break statement
case 'e':
 ++eCnt;  //oops:should bave a break statement

 .....(省略了)
}

为了搞清楚该程序导致了什么结果,假设ch的值是'i'来跟踪这个版本的代码.程序从case'i'后面的语句开始执行,iCnt的值加1.但是,程序的执行并没有在这里停止,而且是越过case标号继续执行,同时将oCnt和uCnt的值都加了1.如果ch是'e'的话,那么eCnt、iCnt、oCnt以及uCnt的值都会加1.

-----------------------------------------------------------我是华丽的分割线------------------------------------------------

小心:对于switch结构,漏写break语句是常见的程序错误.

实践告诉你:尽管没有严格要求switch结构的最后一个标号之后指定break语句,但是,为了安全起见,最好在每个标号后面提供一个break语句,即使是最后一个标号也一样.如果以后在switch结构的末尾又需要添加一个新的case标号,则不用再在前面加break语句了.

----------------------------------------------------------我是华丽的分割线-----------------------------------------------

慎用break语句,它并不总是恰当的

有这么一种常见的情况,程序员希望在case标号后省略break语句,允许程序向下执行多个case标号.这时,两个或多个case值由相同的动作序列来处理.由于系统限定一个case标号只能与一个值相关联,于是为了指定一个范围,典型的做法是,把case标号依次排列.例如,如果只希望计算文本中元音的总数,而不是每一个元音的个数,则可以这样写:

int vowelCnt=0;
// ...
switch(ch)
{
 //any occurrence of a,e,i,o,u increments vowelCnt
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
 ++vowelCnt;
 break;
}

每个case标号不一定要另起一行.为了强调这些case标号表示的是一个要匹配的范围,可以将它们全部在一行中列出:

switch(ch)
{
 //alternative legal syntax
case 'a':case 'e':case 'i':case 'o':case 'u':
 ++vowelCnt;
 break;
}

比较少见的用法是,为了执行某个case的代码后继续执行下一个case的代码,故意省略break语句.

------------------------------------------------------我是华丽的分割线------------------------------------------

实践告诉你:故意省略case后面的break语句是很罕见的,因此应该提供一些注释说明其逻辑.

-----------------------------------------------------我是华丽的分割线-------------------------------------------

原创粉丝点击