语句和块(三)
六、选择语句
选择语句(selection statements)根据控制表达式的值在一组次块代码中选择执行。C语言中选择语句包括if语句和switch语句。
1、if语句
if语句存在以下两种语法格式:
if( controlling-expression ) secondary-block if( controlling-expression ) secondary-block else secondary-block
其中controlling-expression是控制表达式,if语句中控制表达式应具有标量类型(scalar type);secondary-block是次块;if和else是C语言关键词。
if语句流程图如下所示:
if else语句流程图如下所示:
如果if语句控制表达式的值不等于0,将执行第一个次块;如果if语句控制表达式的值等于0,将执行第二个次块。
int i = 1; if(i<0) puts("i is less than 0."); //该语句不会执行。 if(i<3) puts("i is less than 3."); //该语句会执行。 else puts("i is greater than or equal to 3."); //该语句不会执行。
if语句中如果第一个次块是通过标签到达的,第二个次块不会被执行。
int i = 1; if(i<0) { here : puts("i is less than 0."); } else puts("i is greater than or equal to 0."); i += -2; if(i==-1) goto here;
将输出:
i is greater than or equal to 0. i is less than 0.
else与语法上允许的、代码文本中else之前最靠近的if匹配。
if(expression) //A if(expression) //B statements else //else与B处的if匹配。 statements
上述代码等价于:
if(expression) { if(expression) statements else statements }
可以使用大括号({ })改变语法结构。
if(expression) //A { if(expression) //B statements } else //else与A处的if匹配。 statements
2、switch语句
switch语句具有以下语法格式:
switch( controlling-expression ) secondary-block
其中controlling-expression是控制表达式,switch语句中控制表达式应具有整数类型;secondary-block是次块;switch是C语言关键词。
switch语句流程图如下所示:
switch语句中的控制表达式会执行整数提升(integer promotions);每个case标签中的常量表达式应为整型常量表达式,会转换成控制表达式提升后的类型。如果转换后的值与提升后的控制表达式的值匹配,程序执行将跳转到匹配的case标签后的语句或者声明;如果不存在匹配的case标签,但存在default标签,程序执行将跳转到default标签后的语句或者声明。
switch(i) { case 1 : puts("The value of i is 1."); break; case 2 : puts("The value of i is 2."); break; default : puts("The value of i is unknown."); break; }
如果i的值为1,将执行与case 1相关联的次块,与case 2和default相关联的次块不会被执行;如果i的值为2,将执行与case 2相关联的次块,与case 1和default相关联的次块不会被执行;如果i的值为其它值,将执行与default相关联的次块,与case 1和case 2相关联的次块不会被执行。
如果不存在匹配的case常量表达式,并且不存在default标签,switch语句中的任何部分都不会执行。
int i = 3; //switch语句中的任何部分都不会执行。 switch(i) { case 1 : puts("The value of i is 1."); break; case 2 : puts("The value of i is 2."); break; }
转换后同一switch语句中的所有case常量表达式的值应不同,并且同一switch语句最多只能存在一个default标签。
//存在两个相同值的case常量表达式,switch语句非法。 switch(i) { case 0 : puts("The value of i is 0."); break; case false : puts("The value of i is false."); break; default : break; } //不存在default标签,但switch语句是合法的。 switch(i) { case 0 : puts("The value of i is 0."); break; case 1 : puts("The value of i is 1."); break; }
对于嵌套的switch语句,外层switch语句和内层switch语句可以存在各自的default标签;并且内层case常量表达式的值可以与外层case常量表达式的值相同。
struct { int i1; int i2; } s = {1, 1}; switch(s.i1) { case 0 : puts("The value of s.i1 is 0."); break; case 1 : puts("The value of s.i1 is 1."); switch(s.i2) { case 0 : puts("The value of s.i2 is 0."); break; case 1 : puts("The value of s.i2 is 1."); break; default : break; } default : break; }
如果switch语句的任一case标签或者default标签位于可变修改类型(variably modified type)标识符的作用域内,整个switch语句应在该标识符的作用域内;即可变修改类型标识符应在switch语句前声明,或者在switch语句最后一个标签(最后一个标签可以是case标签,也可以是default标签。)后声明。
int n = 3; int x = 2; int a1[n]; //声明合法。 switch(x) { int a2[n]; //声明非法。 case 0 : int a3[n]; //声明非法。 break; case 1 : int a4[n]; //声明非法。 break; default : int a5[n]; //声明合法。 break; int a6[n]; //声明合法。 } int a7[n]; //声明合法。
可变修改类型对象的存储空间通常在其作用域开始时分配,其作用域结束时释放。如果switch语句的case标签或者default标签跳过可变修改类型对象的定义,直接进入其作用域,将会导致未定义行为。