跳转语句
目前我们已经知道如何在循环体之前 ( while
语句和 for
语句) 和之后 (do...while
语句) 设置退出点。然而,有些时候我们也需要在循环的中间设置退出点,甚至可能需要对循环设置多个退出点。break
语句可以满足上述需求。
在学习完 break
语句后,我们将看到两个相关的语句: continue
语句和 goto
语句。由于已经有了 break
和 continue
这样好用的语句,所以现在很少使用 goto
语句了。
break语句
前面已经讨论过, break
可以跳出 switch
语句。break
还可以用于跳出 while
,do...while
或者 for
循环。比如,我们可以通过下面的代码测试 n 是否为素数:
for (d = 2; d < n; d++) {
if (n % d == 0)
break;
}
if (d < n)
printf("%d is divisible by %d\n", n, d);
else
printf("%d is prime\n", n);
break 语句经常使用在 while (1)
这样的语句中,在满足特定的条件时退出循环,以免出现死循环。如:
while (1) {
printf("Enter a number (enter 0 to stop): ");
scanf("%d", &n);
if (n == 0)
break;
printf("%d squared is %d\n", n, n * n);
}
break
可以跳出 switch
, while
, do...while
和 for
语句。但是当这些语句嵌套时, break
只能跳出包含 break
语句的最内层嵌套。如:
while (...) {
switch (...) {
...
break;
...
}
}
上述 break
语句只能将控制从 switch
语句中转移出来,但是不能跳出 while
循环。
(思考:如何跳出外层的 while 语句?)
程序实例
#include <stdio.h>
#include <stdlib.h>
int main() {
int i = 0;
while (1) {
i++;
printf("i = %d\n", i);
if (i == 10) {
break;//跳出while循环
}
}
int flag = 0;
int m = 0;
int n = 0;
for (m = 0; m < 10; m++) {
for (n = 0; n < 10; n++) {
if (n == 5) {
flag = 1;
break;//跳出for (n = 0; n < 10; n++)
}
}
if (flag == 1) {
break;//跳出for (m = 0; m < 10; m++)
}
}
return 0;
}
程序输出:
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10
在switch条件语句和循环语句中都可以使用break语句:
- 当它出现在switch条件语句中时,作用是终止某个case并跳出switch结构。
- 当它出现在循环语句中,作用是跳出当前内循环语句,执行后面的代码。
- 当它出现在嵌套循环语句中,跳出最近的内循环语句,执行后面的代码。
continue语句
break 语句会把控制转移到整个循环的后面,而 continue 会将控制转移到循环的末尾。 break 语句会跳出循环,而 continue 语句仍然留在循环体内。break 语句和continue 语句还有另外一个区别:break 语句可以用于 switch 语句和循环,而continue 只能用于循环。
下面我们通过一个例子来说明这一点:对 10 个非零的整数进行求和。
count = 0;
sum = 0;
while (count < 10) {
scanf("%d", &i);
if (i == 0)
continue;
sum += i;
count++;
/* continue jumps to here */
}
对应的 for 语句是这样:
for (count = 0, sum = 0; count < 10; ) {
scanf("%d", &i);
if (i == 0)
continue;
sum += i;
count++;
/* continue jumps to here */
}
goto语句
break 和 continue 语句都是受限制的,break 只能跳出到 switch 语句或者循环语句后面的那一点,而 continue 语句只能跳转到循环体的末尾。goto 语句就没有这些限制,它可以跳转到函数中任何有标号的语句处。它的唯一限制是只能在函数内进行跳转。
标号是放置在语句开始处的标识符:
identifier: statement
一条语句可以有多个标号。
goto语句的格式如下:
goto identifier;
很显然,我们可以用 goto 语句来实现 break 或者是 continue 的效果 (但是不推荐这么做)。
for (d = 2; d < n; d++)
if (n % d == 0)
goto done;
done:
if (d < n)
printf("%d is divisible by %d\n", n, d);
else
printf("%d is prime\n", n);
在早期的编程语言中,goto 语句还是很常见的,但是现在基本上已经很少使用了(why?)。break, continue, return 语句以及 exit 函数足以应付 goto 语句的大多数使用场景。
虽然如此,但是 goto 语句偶尔还是很有用的。考虑前面提到过的 switch 语句嵌套在 while 语句的场景,break 语句是不可以跳出 while 循环的,但是 goto 语句可以解决这个问题:
while (...) {
switch (...) {
...
goto loop_done;
...
}
}
loop_done:
...
在 C 语言中,goto 语句也常用于进行错误处理。
if (...) { /* check whether error happens */
goto err;
}
...
err:
/* handle errors */
无条件跳转,尽量少用!
#include <stdio.h>
#include <stdlib.h>
int main() {
goto End;//⽆条件跳转到End的标识
printf("aaaaaaaaa\n");
End:
printf("bbbbbbbb\n");
return 0;
}
程序输出:
bbbbbbbb
小练习
许多简单的交互式程序都是基于菜单的:它们向用户显示可供选择的命令列表;一旦用户选择了某条命令,程序就执行相应的操作,然后提示用户输入下一条命令;这个过程一直会持续到用户选择 "退出" 或 "停止" 命令。
这类程序的核心显然是循环。循环内将有语句提示用户输入命令,读命令,然后确定执行的操作:
for (; ;) {
提示用户输入命令;
读入命令;
执行命令;
}
执行命令将用到 switch 语句 (或者级联式 if 语句):
for (; ;) {
提示用户输入命令;
读入命令;
switch (命令) {
case 命令1: 执行操作; break;
case 命令2: 执行操作; break;
...
case 命令n: 执行操作; break;
default: 显示错误信息; break;
}
}
现在请开发一个记账程序。程序将为用户提供选择菜单:清空账户余额,往账户上存钱,从账户上取钱,显示当前余额,退出程序。选择项分别用整数 0、1、2、3 和 4 表示。程序的会话类似这样:
TODO:写出该程序