Skip to content

循环语句

在 C 语言中,每个循环语句都有一个控制表达式。每次执行循环体时,都要对控制表达式求值。如果表达式为真,那么继续执行循环语句;否则执行循环语句的下一条语句。

C 语言提供了 3 种循环语句,即 while 语句, do...while 语句和 for 语句。

while 语句在循环体执行之前测试控制表达式, do...while 循环在循环体执行之后测试控制表达式, for 语句则非常适合那些递增或递减计数变量的循环。

while语句

在所有循环语句中, while 语句是最简单也是最基本的。

while 语句的格式如下:

cpp
while (expr) statment

其中圆括号内的表达式称为控制表达式,圆括号后面的语句是循环体。下面是一个示例:

cpp
i = 1;
while (i < n)
    i = i * 2;

虽然循环体必须是单独的一条语句,但这只是个技术问题:如果需要多条语句,那么只要用一对花括号构造一条复合语句就可以了:

cpp
i = 10;
while (i > 0) {
    printf("Counting down: %d\n", i);
    --i;
}

程序实例

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

int main() {
    int a = 20;

    while (a > 10) {
        scanf("%d", &a);
        printf("a = %d\n", a);
    }

    return 0;
}

程序输出:

shell
20↙️
a = 20
30↙️
a = 30
10↙️
a = 10

无限循环

如果控制表达式的值始终非零,那么 while 语句将永远执行下去。事实上,有时候我们会故意用非零的常量表达式作为控制表达式,以此来构造无限循环。

cpp
// idiom
while (1) ...

除非循环体内含有跳出循环的控制语句 (break, goto, return) 或者调用了导致程序终止的函数,否则上述形式的 while 语句将永远执行下去。

do…while语句

do...while 语句和 while 语句关系紧密。事实上, do...while 语句本质上就是 while 语句,只不过其控制表达式是在每次执行完循环体之后进行判定的。

do...while 语句的格式如下:

cpp
do statment while (expr);

执行 do...while 语句时,先执行循环体,再计算控制表达式的值。如果表达式的值非零,那么继续执行循环体,然后再计算表达式的值;如果表达式的值为零,则终止 do...while 语句的执行。如:

cpp
i = 10;
do {
    printf("Counting down: %d\n", i);
    --i;
} while (i > 0);

TIP

do...while 语句和 while 语句的唯一区别是:do...while 语句的循环体至少会执行一次,而 while 语句在控制表达式的值初始为 0 时,一次都不会执行。

程序实例

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

int main() {
    int a = 1;

    do {
        a++;
        printf("a = %d\n", a);
    } while (a < 10);

    return 0;
}

程序输出:

shell
a = 2
a = 3
a = 4
a = 5
a = 6
a = 7
a = 8
a = 9
a = 10

小练习

编写一个程序计算一个整数的位数。

TODO

for语句

现在介绍 C 语言中最后一种循环,也是功能最强大的一种循环: for 语句。for 语句非常适合那些递增或递减计数变量的循环,当然它也可以灵活地应用在许多其他类型的循环中。for 语句的格式如下:

cpp
for (expr1; expr2; expr3) statement

下面是一个例子:

cpp
for(i = 10; i > 0; i--)
    printf("Counting down: %d\n"; i);

执行 for 语句时,变量 i 先初始化为 10,接着判定 i 是否大于 0。因为 10 > 0,因此 打印 Counting down: 10,然后变量 i 自减。随后再次对条件 i > 0 进行判定...

程序实例

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

int main() {
    int i;
    int sum = 0;

    for (i = 0; i <= 100; i++) {
        sum += i;
    }

    printf("sum = %d\n", sum);

    return 0;
}

程序输出:

shell
sum = 5050

从上面的例子,我们可以看到 for 语句和 while 语句关系非常紧密。事实上,除了一些极少数的情况以外(你能举出例子吗?), for 循环总可以用等价的 while 循环替换:

cpp
expr1;
while (expr2) {
    statement
    expr3;
}

从等价的 while 循环可以看出,expr1 是循环开始执行前的初始化步骤,只执行一次;expr2 是控制循环终止的;expr3 是每次循环中最后被执行的一个操作。

省略for语句中的表达式

for 语句远比现在看到的更加灵活,C 语言允许 for 语句省略一些或者是全部的表达式。

如果省略 expr1,那么在执行循环前没有初始化的操作:

cpp
i = 10;
for (; i > 0; --i)
    printf("Counting down: %d\n", i);

如果省略 expr3,那么循环体需要确保 expr2 的值最终会变成 0:

cpp
for (i = 10; i > 0; )
    printf("Counting down: %d\n", i--);

当同时省略 expr1expr3 时,那么 for 语句和 while 语句就没有任何分别,如:

cpp
i = 10;
for (; i > 0; )
    printf("Counting down: %d\n", --i);

等价于

cpp
i = 10;
while (i > 0)
    printf("Counting down: %d\n", --i);

如果省略 expr2,那么它的默认值为真。例如,某些程序员利用下列的 for 语句建立无限循环:

cpp
// idiom
for ( ; ; ) ...

C99中的for语句

在 C99 中,for 语句的第一个表达式可以替换为一个声明,这一特性使得程序员可以声明一个用于循环的变量:

cpp
for (int i = 0; i < n; ++i)
    ...

变量 i 不需要在该语句前进行声明。如果变量 i 在之前已经进行了声明,这个语句将创建一个新的 i,且该变量只能在循环内使用。

for 语句声明的变量在循环外是不可见的:

cpp
for (int i = 0; i < n; ++i) {
    ...
    printf("%d", i); /* legal */
    ...
}
printf("%d", i); /* Wrong */

TIP

for 语句自己声明循环控制变量通常是一个好办法:这样很方便,而且程序的可读性更强。

顺便提一下,for 语句可以声明多个变量,只要它们的类型相同:

cpp
for (int i = 0, j = 0; i < n; i++)
    ...

逗号表达式

有时候,我们可能需要编写有两个 (或更多个) 初始表达式的 for 语句,或者希望在每次循环时对几个变量进行自增操作。这时我们就需要使用逗号表达式了。

逗号表达式的格式如下:

cpp
expr1, expr2

逗号表达式的求值分为两步:第一步,计算 expr1 并且扔掉计算出的值;第二步,计 算 expr2,把这个值作为整个表达式的值。对 expr1 的计算应该产生一些副作用,否 则 expr1 就没有存在的必要了。举个例子:

cpp
i = 1;
j = 5;
k = (++i, i + j);

逗号表达式是左结合的,因此编译器会把表达式

cpp
i = 1, j = 2, k = i + j

解释为

cpp
(i = 1, j = 2), k = i + j

C/C++ 之所以提供逗号运算符,是为了在只能有一个表达式的地方可以使用两个甚至是多个表达式。换句话说,逗号运算符允许将两个表达式"粘"在一起,构成一个表达式 (和复合语句类似,复合语句可以把一组语句当成一条语句来使用)。

例如,我们可以把原来的程序

cpp
sum = 0;
for (i = 1; i <= N; i++)
    sum += i;

改写成这样:

cpp
for (sum = 0, i = 1; i <= N; i++)
    sum += i;

嵌套循环

循环语句之间可以相互嵌套:

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

int main() {
    int num = 0;
    int i, j, k;

    for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++) {
            for (k = 0; k < 10; k++) {
                printf("hello world\n");
                num++;
            }
        }
    }

    printf("num = %d\n", num);

    return 0;
}

程序输出:

shell
hello world
hello world
...
hello world
num = 1000