char ch;
cin>>ch;
switch (ch)
{
case 'a':
++aCount;
case 'b':
++bCount;
case 'c':
++cCount;
}
cout<<aCount<<endl<<bCount<<endl<<cCount<<endl;
输入a,输出为1 1 1
输入b,输出为0 1 1
输入c,输出为0 0 1
输入d,输出为0 0 0
执行完一个case后,如果未遇到break,会顺次执行后面的case,直到遇到break或switch结束为止。
存在一个普遍的误解:以为程序只会执行匹配的 case 标号相关联的语句。实际上,程序从该点开始执行,并跨越 case 边界继续执行其他语句,直到 switch 结束或遇到 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 语句。
哪怕没有语句要在 default 标号下执行,定义 default 标号仍然是有用的。定义 default 标号是为了告诉它的读者,表明这种情况已经考虑到了,只是没什么要执行的。
一个标号不能独立存在,它必须位于语句之前。如果 switch 结构以 default 标号结束,而且 default 分支不需要完成任何任务,那么该标号后面必须有一个空语句。
switch (ch)
{
case 'a':
++aCount;
case 'b':
++bCount;
case 'c':
++cCount;
default:
;
}
如果default语句下没有“;”,编译会出错。
switch 求解的表达式可以非常复杂。特别是,该表达式也可以定义和初始化一个变量:
switch(int ival = get_response())
在这个例子中,ival 被初始化为 get_response 函数的调用结果,其值将要与每个 case 标号作比较。变量 ival 始终存在于整个 switch 语句中,在 switch 结构外面该变量就不再有效了。
case 标号必须是整型常量表达式。例如,下面的标号将导致编译时的错误:
// illegal case label values
case 3.14: // noninteger
case ival: // nonconstant
如果两个 case 标号具有相同的值,同样也会导致编译时的错误。
对于 switch 结构,只能在它的最后一个 case 标号或 default 标号后面定义变量:
case true:
// error: declaration precedes a case label
string file_name = get_file_name();
break;
case false:
// ...
制定这个规则是为避免出现代码跳过变量的定义和初始化的情况。
回顾变量的作用域,变量从它的定义点开始有效,直到它所在块结束为止。现在考虑如果在两个 case 标号之间定义变量会出现什么情况。该变量会在块结束之前一直存在。对于定义该变量的标号后面的其他 case 标号,它们所关联的代码都可以使用这个变量。如果 switch 从那些后续 case 标号开始执行,那么这个变量可能还未定义就要使用了。
在这种情况下,如果需要为某个特殊的 case 定义变量,则可以引入块语句,在该块语句中定义变量,从而保证这个变量在使用前被定义和初始化。
case true:
{
// ok: declaration statement within a statement block
string file_name = get_file_name();
// ...
}
break;
case false:
// ...