飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 编程基础概念

    • 冯·诺依曼体系结构
    • 数据在计算机中的表示
    • 编程语言的层次
    • C语言的起源与发展
    • C99标准的主要改进
    • 开发环境搭建
    • 第一个C程序
    • 编译与运行流程
    • 可移植性风险的三级体系
  • 第2章 数据类型与运算

    • 字符集与标识符
    • 关键字
    • 注释
    • char 类型
    • short 与 int
    • long 与 long long
    • 有符号与无符号
    • 取值范围与 limits.h
    • float 与 double
    • long double
    • _Bool 类型
    • 变量声明与定义
    • 常量
    • 转义序列
    • 算术运算符
    • 赋值运算符
    • 自增自减运算符
    • 关系与判等运算符
    • 逻辑运算符
    • 位运算符
    • 条件运算符
    • 逗号运算符
    • 运算符优先级
    • 隐式类型转换
    • 显式类型转换
  • 第3章 控制流

    • 表达式语句与空语句
    • 复合语句
    • if 语句
    • switch 语句
    • while 循环
    • do-while 循环
    • for 循环
    • break 与 continue
    • goto 语句
    • return 语句
  • 第4章 函数与模块化编程

    • 函数定义
    • 函数声明与原型
    • main 函数
    • 函数调用机制
    • 传值调用
    • 数组参数
    • 作用域
    • 存储期
    • 链接属性
    • static 与 extern
    • 递归
    • 头文件与源文件
    • 头文件保护
    • include 规则
  • 第5章 数组与字符串

    • 一维数组声明与初始化
    • 数组的存储模型
    • 数组访问与越界
    • 数组操作
    • 二维数组
    • 变长数组 VLA
    • 字符串基础
    • 字符串输入输出
    • 字符串处理函数
    • 字符串与数字转换
  • 第6章 指针

    • 指针的概念
    • 指针的声明与使用
    • 指针运算
    • const 与指针
    • 数组名与指针
    • 指针遍历数组
    • 指针与多维数组
    • 指针作为函数参数
    • 函数返回指针
    • 函数指针
    • 二级指针
    • 复杂声明解析
  • 第7章 结构体、联合体与枚举

    • 结构体定义与声明
    • 结构体初始化
    • 结构体成员访问
    • 结构体嵌套
    • 结构体指针
    • 结构体与函数
    • 联合体
    • 联合体与类型双关
    • 枚举类型
    • 位域
    • 内存对齐与填充
  • 第8章 动态内存管理

    • malloc 与 free
    • calloc 与 realloc
    • 内存泄漏
    • 悬垂指针
    • 内存分配策略
    • 自定义内存池
    • Valgrind 与内存检测
    • 内存碎片
    • 内存对齐分配
    • 常见内存错误
  • 第9章 文件输入输出

    • 文件打开与关闭
    • 文本读写
    • 格式化输入输出
    • 二进制读写
    • 文件定位
    • 错误处理
    • 标准流
    • 临时文件
    • 文件操作示例
  • 第10章 预处理器

    • 预处理器基础
    • 宏定义
    • 带参数的宏
    • 条件编译
    • 头文件包含
    • 预定义宏
    • 宏的高级技巧
    • 预处理器陷阱
    • 编译器特定扩展
  • 第11章 标准库概览

    • 标准库概述
    • assert.h
    • ctype.h
    • errno.h
    • float.h
    • limits.h
    • locale.h
    • math.h
    • setjmp.h
    • signal.h
    • stdarg.h
    • stddef.h
    • stdlib.h
  • 第12章 进阶主题

    • 内联函数
    • 变长数组 VLA
    • 复数类型
    • 布尔类型
    • stdint 与 inttypes
    • 灵活数组成员
    • 匿名结构体与联合体
    • 静态断言
    • 线程支持
    • 原子操作

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 */

执行流程:

  1. 执行初始化(只执行一次)
  2. 判断条件,为假则退出循环
  3. 执行循环体
  4. 执行更新
  5. 回到步骤 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 层,否则考虑重构
上一页
do-while 循环
下一页
break 与 continue