|
第三章 控制流
3.1 语句与程序块
在x=0、i++或printf(…)这样的 表达式 的 后面 加上一个 分号(;)),它们就变成了语句。
x = 0;
i++;
printf(...) ;
在 C 语言中,分号 是语句 结束符。
用一对花括号 { 与 } 把 一组声明 和 语句 括在一起就构成了一个 复合语句(也叫作程序块),复合语句在语法上 等价于单条语句 。
在 任何程序块 中都可以声明变量。右花括号用于结束程序块,其后 不需要分号。
3.2 if-else语句
if-else 语句用于 条件判定。其语法如下所示:
if (表达式)
{
语句1
}
else
{
语句2
}
其中 else 部分是 可选 的。该语句执行时,
先计算表达式的值,如果其值为 真(即表达式的值为 非0),则执行 语句1;
如果其值为 假(即表达式的值为0),并且该语句包含else 部分,则执行 语句2
当判断的条件是 表达式 != 0 这类的条件时,通常使用使用
if (表达式)
代替
if (表达式 != 0)
由于 else 是可选语句
所以在嵌套的 if 语句中省略它的 else 部分将会引发歧义
else 部分与 内层 的 if 匹配。这样的结果不是我们需要的,这就需要添加花括号来强制配对,如下所示
if (n > 0) {
if (a > b)
z = a;
}
else
z = b;
下列代码有 更为严重的歧义,且不容易发现
if (n >= 0)
for (i = 0; i < n; i++)
if (s > 0) {
printf(&#34;...&#34;);
return i;
}
else // 该else与内部的if进行配对的。
printf(&#34;err -- n is negative\n&#34;)
3.3 else-if语句
在 C 语言中我们会经常用到下列结构:
if (表达式1)
语句块1;
else if (表达式2)
语句块2;
else
语句块3;
在这种结构中,else if语句至少0,else语句可选。
在这种结构中,表达式i 会从上到下依次求值,直到遇到 表达式i 的值为真(表达式i非零),执行对应的 表达式i 下的代码后就 终止 整个语序的执行。如果所有的表达式的值 均为假,则执行 else 对应的语句块(如果存在else)
else部分也可以用来 检查错误 ,以 捕获“不可能”的条件。
3.4 switch语句
switch 语句是一种 多路 判定语句,它测试表达式是否与一些常量整数值 匹配,并 执行 相应的 分支动作。
switch(表达式) {
case 常量表达式: 语句序列;
case 常量表达式: 语句序列;
default: 语句序列;
}
每一个分支都由 一个或多个整数值常量或常量表达式 标记。
如果某个 分支与表达式 的值 匹配 ,则从该分支开始执行。
各分支表达式 必须互不相同。
如果没有哪一分支能匹配表达式,则执行标记为 default 的分支。default 分支是 可选 的。
如果没有 default 分支也没有其他分支与表达式的值匹配,则该switch 语句 不执行 任何动作。
各分支及 default 分支的 排列次序是任意的。
下面我们用switch 语句编写程序 用于统计各个数字、空白符及其他所有字符出现的次数:
#include <stdio.h>
int main() {
int c, i, nwhite, nother, ndigit[10];
nwhite = nother = 0;
for (i = 0; i < 10; i++) {
ndigit = 0;
}
while ((c = getchar()) != EOF) {
switch(c) {
case &#39;0&#39;: case &#39;1&#39;: case &#39;2&#39;: case &#39;3&#39;: case &#39;4&#39;:
case &#39;5&#39;: case &#39;6&#39;: case &#39;7&#39;: case &#39;8&#39;: case &#39;9&#39;:
ndigit[c - &#39;0&#39;]++;
break;
case &#39; &#39;:
case &#39;\n&#39;:
case &#39;\t&#39;:
nwhite++;
break;
default:
nother++;
break;
}
}
printf( &#34;aigits =&#34;);
for (i =0;i < 10;i++)
printf(&#34;%a&#34;, ndigit);
printf(&#34;,white space =%d,other = %d\n&#34;, nwhite, nother);
return 0:
}
break 语句将导致程序的执行立即从 switch 语句中退出。在switch 语句中,case 的作用只是一个 标号,因此,某个分支中的代码执行完后,程序将 进入下一分支 继续执行,除非在程序中 显式地跳转。跳出 switch 语句最常用的方法是使用break 语句与 return 语句。
依次执行各分支的做法有优点也有缺点。好的一面是它可以把 若干个分支组合在一起完成一个任务。但是,正常情况下为了防止直接进入下一个分支执行,每个分支后必须 以一个 break 语句结束。从一个分支直接进入下一个分支执行的做法并不健全,这样做在程序修改时很容易出错。应尽量减少从一个分支直接进入下一个分支执行这种用法,在不得不使用的情况下应该加上适当的程序注释。
在 switch 语句最后的分支通常是 default, 同时 default分支结束后也应当添加一个break(尽管没有必要)
3.5 while循环与for循环
在 while 循环语句
while (表达式)
语句
中,首先 求表达式的值。如果其值为真 (非0),则执行语句,并再次求该表达式的值。这一循环过程一直进行下去,直到该表达式 的值为 假(0)时,结束循环。
在 for 循环语句
for(表达式1; 表达式2; 表达式3)
语句
从语法角度看,for 循环语句的 3 个组成部分都是 表达式。最常见的情况是,表达式1与 表达式3 是 赋值表达式或函数调用, 表达式2是 关系表达式。这3个组成部分中的任何部分都可以 省略 ,但 分号必须保留。如果在 for 语句中省略 表达式1 与 表达式3 ,它就退化成了 while 循环语句。如果省略测试条件,即表达式,,则认为其值永远是真值,因此,下列for循环语句:
for(;;){
...
}
是一个“无限”循环语句,这种语句需要借助其他手段(如 break 语句或 return 语句)才能终止执行。
3.6 do-while循环
while 和 for 循环都是在执行循环体之前就测试 循环结束条件,但是C语言提供了一种先执行循环,然后测试 循环结束条件 的语句do-while语句。它的语法形式如下:
do {
语句
}while(表达式)
这样就保证了 循环体至少执行了一次
在这一结构中,先执行 循环体中的 语句 部分,然后再求 表达式的值。
如果表达式的值为 真,则再次执行语句。
表达式的值变为 假,则循环终止。
3.7 break语句与continue语句
break 语句能使程序从 switch 语句或 当前循环 中立即 跳出。
下面示例代码
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 5; j++) {
if (j + i == 7)
break;
}
}
中,该 break 语句是 跳出 break 所在的一层 循环。
continue 语句 用于使 循环语句 开始下一次 循环的执行 (也就是,跳过正在执行循环,continue之后的语句将不在执行)。
下面示例代码
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 5; j++) {
if (j + i == 7)
continue;
printf(&#34;hello %d\n&#34;, i + j);
}
}
中,如果执行到了 continue 语句,它后面所有代码(printf(&#34;...&#34;))将不会在执行。转而执行下一次循环。
continue 不会跳出循环,只是跳过当前执行的循环。
3.8 goto语句与标号
C 语言提供了可随意滥用的 goto 语句以及 标记 跳转位置的标号。从理论上讲,goto 语句是没有必要的,实践中不使用 goto 语句也可以很容易地写出代码。
通常是在下列这种深度嵌套的语句中,用于结束嵌套时使用。
for(...) {
for(...) {
for(...) {
if (disaster)
goto error;
}
}
}
error:
处理错误情况
goto 语句的大量使用,会导致程序难以理解,建议尽可能少地使用goto 语句。 |
|