Skip to content

跳转语句

目前我们已经知道如何在循环体之前 ( while 语句和 for 语句) 和之后 (do...while 语句) 设置退出点。然而,有些时候我们也需要在循环的中间设置退出点,甚至可能需要对循环设置多个退出点。break 语句可以满足上述需求。

在学习完 break 语句后,我们将看到两个相关的语句: continue 语句和 goto 语句。由于已经有了 breakcontinue 这样好用的语句,所以现在很少使用 goto 语句了。

break语句

前面已经讨论过, break 可以跳出 switch 语句。break 还可以用于跳出 while ,do...while 或者 for 循环。比如,我们可以通过下面的代码测试 n 是否为素数:

cpp
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) 这样的语句中,在满足特定的条件时退出循环,以免出现死循环。如:

cpp
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...whilefor 语句。但是当这些语句嵌套时, break 只能跳出包含 break 语句的最内层嵌套。如:

cpp
while (...) {
    switch (...) {
            ...
                break;
            ...
    }
}

上述 break 语句只能将控制从 switch 语句中转移出来,但是不能跳出 while 循环。

(思考:如何跳出外层的 while 语句?)

程序实例

c
#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;
}

程序输出:

shell
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 个非零的整数进行求和。

cpp
count = 0;
sum = 0;
while (count < 10) {
    scanf("%d", &i);
    if (i == 0)
        continue;
    sum += i;
    count++;
    /* continue jumps to here */
}

对应的 for 语句是这样:

cpp
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 语句就没有这些限制,它可以跳转到函数中任何有标号的语句处。它的唯一限制是只能在函数内进行跳转。

标号是放置在语句开始处的标识符:

cpp
identifier: statement

一条语句可以有多个标号。

goto语句的格式如下:

cpp
goto identifier;

很显然,我们可以用 goto 语句来实现 break 或者是 continue 的效果 (但是不推荐这么做)。

cpp
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 语句可以解决这个问题:

cpp
while (...) {
    switch (...) {
            ...
                goto loop_done;
            ...
    }
}
loop_done:
...

在 C 语言中,goto 语句也常用于进行错误处理。

cpp
if (...) { /* check whether error happens */
    goto err;
}
...
    err:
/* handle errors */

无条件跳转,尽量少用!

c
#include <stdio.h>
#include <stdlib.h>

int main() {
    goto End;//⽆条件跳转到End的标识
    printf("aaaaaaaaa\n");
End:
    printf("bbbbbbbb\n");

    return 0;
}

程序输出:

shell
bbbbbbbb

小练习

许多简单的交互式程序都是基于菜单的:它们向用户显示可供选择的命令列表;一旦用户选择了某条命令,程序就执行相应的操作,然后提示用户输入下一条命令;这个过程一直会持续到用户选择 "退出" 或 "停止" 命令。

这类程序的核心显然是循环。循环内将有语句提示用户输入命令,读命令,然后确定执行的操作:

cpp
for (; ;) {
    提示用户输入命令;
    读入命令;
    执行命令;
}

执行命令将用到 switch 语句 (或者级联式 if 语句):

cpp
for (; ;) {
    提示用户输入命令;
    读入命令;
    switch (命令) {
        case 命令1: 执行操作; break;
        case 命令2: 执行操作; break;
            ...
                case 命令n: 执行操作; break;
        default: 显示错误信息; break;
    }
}

现在请开发一个记账程序。程序将为用户提供选择菜单:清空账户余额,往账户上存钱,从账户上取钱,显示当前余额,退出程序。选择项分别用整数 0、1、2、3 和 4 表示。程序的会话类似这样:

TODO:写出该程序