c 语言switch结尾,C存在fall through的switch语句

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

switch语句的一般形式如下:1

2

3

4

5switch(表达式){

case 常量表达式:零条或多条语句

case 常量表达式:零条或多条语句

default: 零条或多条语句

}

一个遵循标准的C编译器至少允许一条switch语句中有257个case标签(ANSI C标准),这是为了允许switch满足一个8bit字符的所有情况(256个可能的值加上EOF)。

每个case结构由3部分组成:关键字case;紧随其后的常量值或常量表达式;再紧接一个冒号。看一个例子:1

2

3

4

5

6

7

8

9

10

11int main(){

int i=0,j=0;

const int a = 2;

switch(i){

case 1: j=1;

case a: j=2;

case 3: j=3;

default: j=4;

}

return 0;

}

编译出错:

case a: j=2;

error: case label does not reduce to an integer constant

从这里不仅可以看出const修饰的变量并不代表就是常量,而且case后面必须为常量值或常量表达式。

a.当表达式的值与case中的常量匹配时,该case后面的语句就会执行。

b.default(如果有的话)可以出现在case列表的任意位置,但习惯上总是把default放在最后,它在其他的case均无法匹配时被选中执行。

c.如果没有default,而且所有的case均不匹配,那整条switch语句便什么都不做。

switch存在的问题:

其一:可以在switch的左花括号之后声明一些变量,但变量不会被初始化。

例如,可以在switch的左花括号之后声明一些变量,从而进行一些局部存储的分配。在最初的编译器里,这是一个技巧——绝大多数用于处理任何复合语句的代码都可以被复用,可以用于处理switch语句中由花括号包住的那部分代码。所以在这个位置上声明一些变量会被编译器很自然的接受,尽管在switch语句中为这些变量加上初始值是没有什么用处的,因为它绝不会被执行——语句从匹配表达式的case开始执行。示例如下:1

2

3

4

5

6

7

8

9

10

11

12

13int main(){

int i=0,j=0;

switch(i){

int a = 2;

case 1: j=1;

case 2: j=2;

case 3: j=3;

default: j=4;

printf("%dn",a);

}

printf("%dn",j);

return 0;

}

编译时警告:

printf(“%dn”,a);

warning: ‘a’ is used uninitialized in this function [-Wuninitialized]

运行结果显示:

0

4

在C语言中,当建立一个块时,一般总是这样开始的:

{

语句

}

你总是可以在两者之间增加一些声明,如:

{

声明

语句

}

当分配动态内存代价较高时,你可能会采用这种局部存储的方法,但有可能的话要尽量避免,编译器可以自由的忽略它,它可以通过函数调用来分配所有局部块需要的内存空间。

另一种用法是声明一些完全局部于当前块的变量:1

2

3

4

5

6

7

8

9

10int main(){

int a = 2,b = 1;

if(a > b){

int temp = a;

a = b;

b = temp;

}

printf("a = %d, b = %dn",a,b);

return 0;

}

运行输出:

a = 1, b = 2

若增加代码:1

2

3

4

5

6

7

8

9

10

11int main(){

int a = 2,b = 1;

if(a > b){

int temp = a;

a = b;

b = temp;

}

printf("temp = %dn",temp);

printf("a = %d, b = %dn",a,b);

return 0;

}

编译出错:

printf(“temp = %dn”,temp);

error: ‘temp’ undeclared (first use in this function)

可见,变量temp完全局部于if语句的代码块。

C++在这方面又进了一步,允许语句和声明以任意的顺序出现,甚至允许变量的声明出现在for表达式的内部:1for(int i = 0; i<100; i++){ ... }

其二:switch内部任何语句都可以加上标签。

switch内部任何语句都可以加上标签,并在执行时跳转到那里,这就有可能破坏进程流的结构化。示例:1

2

3

4

5

6

7

8

9

10int main(){

int i = 2;

switch(i){

case 5+3: do_again:

case 2: printf("loopn");goto do_again;

default: i++;

case 3: ;

}

return 0;

}

上述代码执行时,进程循环输出“loop”。

同时,平时在其他地方,为了避免破坏进程流的结构化,应当尽量不要使用goto语句。

其三:对case可能出现的值太过于放纵了。

所有的case都是可选的,任何形式的语句——包括带标签的语句都是允许的。这就意味着有些错误很难检测出来。代码示例:1

2

3

4

5

6

7

8

9

10

11int main(){

int i = 2;

switch(i){

case 5+3: ;

case 2: printf("loopn");

defau1t: i++;

case 3: ;

}

printf("%dn",i);

return 0;

}

上述代码将default的字母l变为数字1,编译警告:

defau1t: i++;

warning: label ‘defau1t’ defined but not used [-Wunused-label]

此时default由语句变为一个标签,进程仍然能够执行,执行输出结果:

loop

3

其四:最大的缺点——fall through

switch不会在每个case标签后面的语句执行完毕后自动终止。一旦执行某个case语句,进程将会依次执行后面所有的case,除非遇到break语句。代码示例:1

2

3

4

5

6

7

8

9

10int main(){

switch(2){

case 1: printf("case 1n");

case 2: printf("case 2n");

case 3: printf("case 3n");

case 4: printf("case 4n");

default: printf("defaultn");

}

return 0;

}

输出结果为:1

2

3

4case 2

case 3

case 4

default

这称之为“fall through”,意思是:如果case语句后面不加break,就依次执行下去,以满足某些特殊情况的要求。但实际上,这是一个非常不好的特性,因为几乎所有的case都需要以break结尾。在大多数情况下,你不希望因这个缺省的行为而不得不加上一条额外的break语句来改变它。

其五:break到底中断了什么。

先看一段有bug的代码:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21int main(){

int i = 2,a = 0,b = 1;

switch(i){

case 1:

printf("case 1n");

break;

case 2:

if(a == 0){

printf("step 1n");

if(b ==1)

break;

printf("step 2n");

}//代码意图是跳到这里

printf("step 3n");

b++;

break;

default: printf("defaultn");

}//事实是跳到这里

printf("b = %dn",b);

return 0;

}

进程输出:

step 1

b = 1

所以,从上面可以体会到,break语句跳出的是最近的那层循环语句或switch语句。if中的break语句使得代码直接跳出switch语句。在C语言中,不要低估”break“语句对控制结构的影响,慎重使用。

故综上,switch语句的一般形式为:1

2

3

4

5

6

7

8

9

10switch(表达式){

case 常量表达式:

零条或多条语句;

break;

case 常量表达式:

零条或多条语句;

break;

default:

零条或多条语句;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值