for 循环
for 循环是 C 语言中最紧凑、最常用的迭代结构,将初始化、条件判断和更新三个要素集中在循环头部。它特别适合已知循环次数的场景,但三个表达式均可省略,使其也能表达各种复杂的循环逻辑。C99 允许在 for 的初始化部分声明变量,且该变量作用域仅限于循环体。
基本语法
for (初始化; 条件; 更新)
语句
for (初始化; 条件; 更新) {
语句1;
语句2;
}
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
/* 输出:0 1 2 3 4 5 6 7 8 9 */
执行流程:
- 执行初始化(只执行一次)
- 判断条件,为假则退出循环
- 执行循环体
- 执行更新
- 回到步骤 2
三个表达式均可省略
for 的三个部分都是可选的,但分号必须保留:
/* 省略初始化 */
int i = 0;
for (; i < 10; i++) {
printf("%d ", i);
}
/* 省略条件 → 无限循环 */
for (int i = 0; ; i++) {
if (i >= 10) break;
printf("%d ", i);
}
/* 省略更新 → 在循环体内更新 */
for (int i = 0; i < 10; ) {
printf("%d ", i);
i++;
}
/* 全部省略 → 无限循环 */
for (;;) {
/* 等价于 while(1) */
if (should_stop()) break;
}
C99 的 for 循环变量声明
C99 允许在 for 的初始化部分声明变量,该变量作用域仅限于循环体:
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
/* printf("%d\n", i); */ /* 错误:i 在循环外不可见 */
这避免了循环变量污染外部命名空间:
int i = 100; /* 外部变量 */
for (int i = 0; i < 5; i++) { /* 内部 i,不影响外部 */
printf("%d ", i); /* 输出 0 1 2 3 4 */
}
printf("%d\n", i); /* 输出 100 */
注意:C89 不支持这种写法,变量必须在外部声明。
逗号运算符在 for 中的应用
逗号运算符可以在初始化和更新部分同时处理多个变量:
/* 同时初始化和更新两个变量 */
for (int i = 0, j = 10; i < j; i++, j--) {
printf("(%d,%d) ", i, j);
}
/* 输出:(0,10) (1,9) (2,8) (3,7) (4,6) */
/* 遍历二维数组 */
int matrix[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
for (int i = 0, count = 0; i < 3; i++) {
for (int j = 0; j < 3; j++, count++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
嵌套 for 循环
for 循环经常嵌套使用,处理多维数据:
/* 打印乘法表 */
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
printf("%d*%d=%2d ", j, i, i * j);
}
printf("\n");
}
/* 遍历字符串数组 */
char *names[] = {"Alice", "Bob", "Charlie"};
for (int i = 0; i < 3; i++) {
for (int j = 0; names[i][j] != '\0'; j++) {
printf("%c", names[i][j]);
}
printf("\n");
}
for 与 while 的等价转换
for 和 while 可以互相转换:
/* for */
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
/* 等价的 while */
int i = 0;
while (i < 10) {
printf("%d\n", i);
i++;
}
选择指南:
- 循环次数已知 →
for - 循环次数未知,由条件控制 →
while - 至少执行一次 →
do-while
常见错误
分号导致空循环体:
for (int i = 0; i < 10; i++); /* 空语句!循环体为空 */
printf("%d\n", i); /* 只执行一次,i 已超出作用域 */
/* 正确 */
for (int i = 0; i < 10; i++) {
printf("%d\n", i);
}
循环变量作用域混淆:
for (int i = 0; i < 10; i++) { }
printf("%d\n", i); /* 错误:i 不可见(C99 模式) */
/* C89 风格 */
int i;
for (i = 0; i < 10; i++) { }
printf("%d\n", i); /* 正确:i 在外部声明 */
更新表达式错误:
for (int i = 0; i < 10; i) { /* 忘记 i++ → 无限循环 */
printf("%d\n", i);
}
for (int i = 0; i < 10; ); /* 更新部分为空语句 */
{ /* 这行不在 for 内 */
printf("%d\n", i);
}
边界错误:
/* 差一错误:执行 11 次 */
for (int i = 0; i <= 10; i++) { }
/* 正确:执行 10 次 */
for (int i = 0; i < 10; i++) { }
/* 从 1 开始 */
for (int i = 1; i <= 10; i++) { } /* 执行 10 次 */
最佳实践
- 已知循环次数时用
for,未知时用while - 利用 C99 的循环内声明,限制变量作用域
- 避免在循环体内修改循环变量(除非有意)
- 循环体始终使用花括号
- 注意边界条件(
<vs<=) - 嵌套循环不宜超过 3 层,否则考虑重构