编译与运行
gcc -std=c11 -Wall -Wextra lesson05.c -o lesson05.exe
./lesson05.exeC foundations / Lesson 05
采集四次数据,不必把相同代码复制四遍。本课从一个能运行的累计程序开始,学习循环的初始化、判断、更新与边界,逐步认识 for、while、do-while。
条件语句决定一次分支;循环在条件允许时反复执行一段代码。学完后,你应当能够:
for、while 与 do-while 在边界情况下执行几次。break 和 continue,检查循环变量是否能走向结束。一个对 1、2、3、4 做累计的小程序和一张手写追踪表。示例数字是模拟数据,尚未读取真实传感器。
lesson05.c先预测程序会打印几行、最后的总和是多少,再输入并运行:
#include <stdio.h>
int main(void)
{
int sum = 0;
for (int sample = 1; sample <= 4; sample++) {
sum = sum + sample;
printf("sample=%d total=%d\n", sample, sum);
}
printf("sum=%d\n", sum);
return 0;
}gcc -std=c11 -Wall -Wextra lesson05.c -o lesson05.exe
./lesson05.exegcc -std=c11 -Wall -Wextra lesson05.c -o lesson05
./lesson05请在源码所在目录运行。预期输出:
sample=1 total=1
sample=2 total=3
sample=3 total=6
sample=4 total=10
sum=10这里 sum 是累计和,不是循环次数。循环结束后,函数体内的最后一条 printf 只执行一次。
sum 开始为 0。每次进入循环体,先执行加法与赋值,再打印当前结果;随后执行更新 sample++,然后重新判断条件。
| 轮次 | 进入循环时 sample | 计算前 sum | 计算后 sum |
|---|---|---|---|
| 1 | 1 | 0 | 1 |
| 2 | 2 | 1 | 3 |
| 3 | 3 | 3 | 6 |
| 4 | 4 | 6 | 10 |
第四轮结束后,更新使 sample 变成 5。判断 5 <= 4 为假,因此循环结束,不会执行第五轮。
for (int sample = 1; sample <= 4; sample++) {
/* 循环体 */
}int sample = 1sample <= 4sample++for (int i = 0; i < 4; i++) 的循环体也执行四次,i 依次为 0、1、2、3。以后遍历数组时,常见的合法下标从 0 到元素数减 1。
三个部分之间用分号分隔。三个表达式都可以省略,但省略条件时不能误以为会自动结束;本课先明确写出条件和更新。
while 在每次执行循环体之前检查条件。下面片段可放进已有 main 中运行:
int attempt = 0;
while (attempt < 3) {
attempt++;
printf("attempt=%d\n", attempt);
}依次输出 attempt=1、attempt=2、attempt=3,随后因为 3 < 3 为假而结束。如果初值就是 3,循环体不会执行。与 for 相比,初始化和更新写在不同位置,更需要主动检查更新是否发生。
如果忘记 attempt++,且没有其他代码改变 attempt,条件会持续为真,程序不会正常走出这个循环。可先画出变量变化,再运行测试。
int count = 3;
do {
printf("count=%d\n", count);
count++;
} while (count < 3);这段代码先打印一次 count=3,再将 count 加到 4,最后判断为假并退出。即使开始时条件为假,循环体仍会执行一次。注意末尾 while (...); 的分号是语法的一部分。
对比:把同样的条件放在普通 while 中,初始 count = 3 时循环体执行零次。选哪种写法取决于任务是否必须先执行一次。
break 退出包含它的最内层循环或 switch;continue 跳过当前循环体剩余部分,进入下一轮所需的处理。下面的片段打印 0 1 3 4,忽略整数 2:
for (int i = 0; i < 5; i++) {
if (i == 2) {
continue;
}
printf("%d ", i);
}
printf("\n");在 for 中,continue 后仍会执行更新表达式 i++,再判断条件。在 while 中,continue 直接进入下一次条件判断;如果更新写在它之后,就会跳过更新,因此应重新检查结束条件。
在嵌套循环中,break 退出包含该语句的最内层循环;若循环内部的 switch 包含这个 break,它只退出该 switch。需要结束外层循环时,应明确设计外层条件或状态。
for (int i = 0; i < 4; i++) 中声明的 i 可用于该循环的条件、更新和循环体;循环结束后不能在循环外直接使用它。如果结束后还需要这个值,可在循环前声明:
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", i);
}
printf("after=%d\n", i); /* 4 */边界是循环中最值得测试的地方:起点、最后一个满足条件的值、第一个不满足条件的值,以及第一次条件就为假的情况。若变量数值可能达到类型范围边界,还要检查更新是否会产生超出范围的结果;不能依赖有符号整数溢出。
| 现象 | 检查点 | 处理 |
|---|---|---|
| 多执行一次 | < 和 <= 的最后一个值不同 | 写出第一轮和最后一轮的变量值。 |
| 一直不退出 | 更新遗漏、方向错误或被 continue 跳过 | 追踪条件与变量变化;先在小范围验证。 |
| 循环体没有执行 | 第一次判断是否已经为假 | 核对初值和比较方向。 |
| 循环外提示变量未声明 | 变量是否声明在 for 内 | 若确需循环外使用,在合适的外层作用域声明。 |
另外,while (condition); 末尾的分号构成空语句;紧随其后的花括号不会成为这个 while 的循环体。应仔细检查多余分号和缩进。
将主例程条件改为 sample < 4,累计输出几轮,最后 sum 是多少?
循环体执行三轮,sample 取 1、2、3,最后 sum=6。
int n = 3; while (n < 3) { n++; } 的循环体执行几次?结束后 n 是多少?
第一次判断就是假,执行零次,n 保持 3。
若在 while 中因为某个值执行 continue,而变量更新位于它后面,会发生什么?
该轮更新会被跳过;如果条件继续为真且状态没有其他变化,可能一直重复。应调整更新位置或设计其他可证明的退出条件。
for 中 continue 之后的更新步骤。接下来进入函数,把重复使用的计算封装为有名字的程序片段。