在C语言编程中,循环结构就像一台精密的流水线机器,能够重复执行特定代码块直到满足终止条件。for循环和do-while循环是两种最常用的循环控制结构,它们看似简单,但实际应用中藏着许多值得注意的细节。
for循环特别适合已知循环次数的场景,比如遍历数组或执行固定次数的计算。它的标准结构包含初始化、条件判断和更新三个部分,这三个部分就像机器的启动按钮、运行指示灯和自动调节阀,共同控制着循环的运转。
而do-while循环则像是一个"先斩后奏"的执行者,它保证循环体至少执行一次,然后再检查条件决定是否继续。这种特性使其特别适合需要先执行操作再验证结果的场景,例如用户输入验证。
一个完整的for循环通常长这样:
c复制for (初始化表达式; 条件表达式; 更新表达式) {
// 循环体
}
但C语言的灵活性允许我们省略这三个部分中的任何一个,甚至全部省略。当条件判断部分被省略时,循环会变成一个无限循环:
c复制for (;;) {
printf("无限循环中...\n");
}
这种写法在嵌入式系统的主循环或服务器的事件监听中很常见,但通常会在循环体内设置break条件来终止。
在C99标准之前,循环变量必须在for语句外部声明:
c复制int i;
for (i = 0; i < 10; i++) {
// ...
}
C99标准引入了在for循环初始化部分声明变量的能力,这种变量的作用域仅限于循环内部:
c复制for (int i = 0; i < 10; i++) {
// i只在此处可见
}
// 此处i不可见
这种写法更符合现代编程习惯,能减少变量污染全局命名空间的风险。
嵌套循环时,内层循环的初始化容易被忽略,导致意外行为:
c复制int i = 0;
int j = 0;
for (; i < 3; i++) {
for (; j < 3; j++) {
printf("i=%d, j=%d\n", i, j);
}
}
这段代码只会完整执行内层循环一次,因为j在第一次循环后已经变为3,后续循环中内层循环的条件直接不满足。正确的做法是在每次外层循环时重新初始化j:
c复制for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("i=%d, j=%d\n", i, j);
}
}
break语句就像循环中的紧急停止按钮,它会立即终止当前循环:
c复制for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
printf("%d ", i); // 输出:1 2 3 4
}
在多层嵌套循环中,break只会跳出当前所在的循环层。如果需要跳出多层循环,通常需要使用标志变量或goto语句(虽然goto要慎用)。
continue语句则像是循环中的跳过当前迭代的指令:
c复制for (int i = 1; i <= 10; i++) {
if (i == 5) {
continue;
}
printf("%d ", i); // 输出:1 2 3 4 6 7 8 9 10
}
需要注意的是,在for循环中使用continue后,更新表达式仍然会执行,这与while循环中的行为不同。
下面两个看似相似的循环,实际执行次数却完全不同:
c复制// 情况1:
for (i = 0, k = 0; k = 0; i++, k++) {
printf("hh\n"); // 不会执行
}
// 情况2:
for (i = 0, k = 0; k == 0; i++, k++) {
printf("hh\n"); // 执行一次
}
关键区别在于条件表达式:k=0是赋值表达式,其值为0(假);而k==0是关系表达式,当k等于0时为真。
计算1!+2!+...+10!有两种典型方法:
c复制// 方法一:双层循环
int result = 0;
for (int i = 1; i <= 10; i++) {
int factorial = 1;
for (int j = 1; j <= i; j++) {
factorial *= j;
}
result += factorial;
}
// 方法二:利用阶乘的递推关系
int result = 0;
int factorial = 1;
for (int i = 1; i <= 10; i++) {
factorial *= i; // i! = (i-1)! * i
result += factorial;
}
方法二的时间复杂度从O(n²)降到了O(n),体现了算法优化的重要性。
do-while循环的语法结构:
c复制do {
// 循环体
} while (条件表达式);
与while循环不同,do-while循环至少会执行一次循环体,因为条件判断是在循环体执行之后进行的。
在do-while循环中使用break和continue需要特别注意:
c复制// break示例
int i = 1;
do {
if (i == 5) break;
printf("%d ", i); // 输出:1 2 3 4
i++;
} while (i < 10);
// continue示例(危险!)
int i = 1;
do {
if (i == 5) continue;
printf("%d ", i); // 输出1 2 3 4后陷入死循环
i++;
} while (i < 10);
continue在do-while中会导致跳过循环体剩余部分,但如果没有在continue前更新循环变量,可能会造成死循环。
使用for循环的场景:
使用do-while循环的场景:
循环结构虽然简单,但在性能敏感的场景中仍需注意:
在实际项目中,我经常使用循环结构来处理数据集合、实现算法逻辑或控制程序流程。理解这些循环的细微差别,能够帮助写出更高效、更可靠的代码。特别是在嵌入式开发中,循环结构的正确使用直接关系到系统的稳定性和响应速度。