Skip to content

C# while 循环:从「重复劳动」到「自动执行」 ​

引言:程序里的「 repeat 键」 ​

想象你每天早上都要做同一件事:「只要闹钟没响,就继续睡觉。」——这就是 while 循环的原型。它不关心睡了几次,只关心「条件是否还满足」。如果换成「睡满 8 小时就起床」,那就是 for 循环的思维。

再看一个反例:如果没有循环,你要打印 100 个数字,就得写 100 行 Console.WriteLine——这是顺序执行代码的弊端:重复、冗长、无法应对变化。而 while 循环把「判断 + 执行」打包成一个自动装置,让程序自己决定什么时候停。

while 循环是 C# 中最灵活的条件循环结构。与 for 的「次数驱动」不同,while 擅长「条件驱动」——当你不知道要循环多少次,只知道「满足什么条件就继续」时,while 是首选。


一、基础语法:极简结构 ​

1.1 语法结构拆解 ​

csharp
while (条件表达式)   // 判断:条件为 true 才执行循环体
{
    // 循环体:重复执行的代码
    // 通常包含更新循环变量的语句,否则可能死循环
}

与 for 的对比:

维度forwhile
结构三表达式集中在一行条件单独一行,初始化和迭代分散
适用已知次数、需要索引未知次数、条件驱动
变量作用域循环变量通常在 for 内部循环变量通常在外部声明

1.2 执行流程分步解析 ​

第 1 步:判断条件表达式
         ├── true  → 执行循环体 → 回到第 1 步
         └── false → 退出循环,继续执行后续代码

关键特征:先判断,后执行。如果条件一开始就是 false,循环体一次都不执行。

1.3 极简入门示例 ​

csharp
// 场景:打印 1 到 5
int i = 1;              // ① 初始化:循环变量在外部声明

while (i <= 5)          // ② 判断:i 是否小于等于 5?
{
    Console.WriteLine($"当前数字:{i}");  // ③ 执行:条件为 true 时执行
    i++;                // ④ 更新:i 自增 1,为下一次判断做准备
}                       // ⑤ 回到 ②,重新判断

// 输出:
// 当前数字:1
// 当前数字:2
// 当前数字:3
// 当前数字:4
// 当前数字:5

逐行执行时机:

行号代码执行时机
①int i = 1;循环开始前,只执行一次
②while (i <= 5)每次循环体执行前都判断
③Console.WriteLine(...)条件为 true 时执行
④i++;循环体最后执行,然后回到 ②

1.4 对比示例:顺序执行 vs while 循环 ​

csharp
// ❌ 顺序执行:重复、冗长、无法扩展
Console.WriteLine("第 1 次执行");
Console.WriteLine("第 2 次执行");
Console.WriteLine("第 3 次执行");
// ... 如果要 100 次,得写 100 行

// ✅ while 循环:简洁、灵活、可扩展
int count = 1;
while (count <= 100)    // 改成 1000 也只需改一个数字
{
    Console.WriteLine($"第 {count} 次执行");
    count++;
}

二、进阶知识点 ​

2.1 循环变量的作用域与更新规则 ​

作用域规则:while 的循环变量通常在循环外部声明,因此循环结束后仍然可用。

csharp
int i = 1;
while (i <= 3)
{
    Console.WriteLine($"循环内:i = {i}");
    i++;
}
Console.WriteLine($"循环后:i = {i}");  // 输出:4(i 仍然可用)

// 对比 for 循环:for 内部声明的变量,循环结束后销毁
// for (int j = 1; j <= 3; j++) { }
// Console.WriteLine(j);  // ❌ 编译错误

更新规则:循环变量必须在循环体内更新,否则条件永远为 true,导致死循环。

csharp
// ❌ 错误:忘记更新循环变量
int k = 1;
while (k <= 3)
{
    Console.WriteLine(k);
    // k++;  // 漏掉了!k 永远是 1,死循环
}

// ✅ 正确:每次循环都更新
int m = 1;
while (m <= 3)
{
    Console.WriteLine(m);
    m++;  // 必须更新
}

2.2 无限循环:正确场景与错误场景 ​

正确应用场景:服务器监听、游戏主循环、实时数据读取。

csharp
// ✅ 正确:服务器监听(直到用户按 ESC)
Console.WriteLine("服务器已启动,按 ESC 退出...");
while (true)  // 无限循环是设计意图
{
    if (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)
    {
        break;  // 显式退出
    }
    Console.WriteLine($"{DateTime.Now:HH:mm:ss} 运行中...");
    Thread.Sleep(1000);
}

错误使用场景:本意是有限循环,却因逻辑错误变成无限循环。

csharp
// ❌ 错误:条件永远为 true(没有退出机制)
int x = 0;
while (x >= 0)  // x 永远 >= 0,死循环
{
    x++;
}

// ❌ 错误:更新方向与条件矛盾
int y = 10;
while (y > 0)
{
    y++;  // y 越来越大,永远 > 0
}

// ✅ 修复:确保条件最终会变为 false
int z = 10;
while (z > 0)
{
    Console.WriteLine(z);
    z--;  // 递减,最终会到 0
}

2.3 break 与 continue 的精准用法 ​

break:立即退出整个循环,不再判断条件。

csharp
// 场景:找到第一个偶数就停止
int num = 1;
while (num <= 10)
{
    if (num % 2 == 0)
    {
        Console.WriteLine($"找到第一个偶数:{num}");
        break;  // 找到后立即退出,不再继续
    }
    num++;
}
// 输出:找到第一个偶数:2

continue:跳过当前轮次,直接进入下一轮判断。

csharp
// 场景:只打印奇数,跳过偶数
int n = 0;
while (n < 10)
{
    n++;
    if (n % 2 == 0)
    {
        continue;  // 偶数跳过,不执行下面的输出
    }
    Console.WriteLine($"奇数:{n}");
}
// 输出:奇数:1、3、5、7、9

对比记忆:

关键字作用类比
break结束整个循环下班走人
continue跳过本次,继续下次跳过这道菜,尝下一道

三、常见坑点与调试方案 ​

3.1 坑点1:死循环的排查方法 ​

症状:程序卡住不动,CPU 占用高。

排查步骤:

csharp
// 步骤1:在循环体内打印变量值,观察变化轨迹
int i = 0;
while (i < 5)
{
    Console.WriteLine($"调试:i = {i}");  // 添加调试输出
    // 如果看到 i 永远不变,说明忘记更新
    // 如果看到 i 朝错误方向变化,说明更新逻辑错误
    i++;
}

// 步骤2:设置最大循环次数保险(开发阶段)
int safety = 0;
while (condition)
{
    if (++safety > 10000)
    {
        throw new Exception("疑似死循环!");
    }
    // 正常逻辑
}

3.2 坑点2:循环变量未更新导致逻辑错误 ​

Bug 案例:

csharp
// ❌ 原意:打印 1-5,实际:死循环
int count = 1;
while (count <= 5)
{
    Console.WriteLine(count);
    // count++;  // 漏掉了!
}

修复演示:

csharp
// ✅ 修复:确保循环体内有更新语句
int count = 1;
while (count <= 5)
{
    Console.WriteLine(count);
    count++;  // 补上更新
}

预防措施:写完 while 后,先检查循环体内是否有变量更新。

3.3 坑点3:条件判断写错引发执行次数异常 ​

Bug 案例:边界条件错误。

csharp
// ❌ 原意:打印 1-5,实际:打印 1-6(多执行一次)
int i = 1;
while (i <= 5)  // 应该是 i < 5 或 i <= 5?
{
    Console.WriteLine(i);
    i++;
}
// 如果原意是 1-4,这里写 <= 5 就错了

// ❌ 原意:打印 1-5,实际:一次都不执行
int j = 1;
while (j > 5)  // 条件写反了,应该是 j <= 5
{
    Console.WriteLine(j);
    j++;
}

修复演示:

csharp
// ✅ 明确边界:用「期望次数」反推条件
// 要执行 5 次:i 从 1 到 5,条件是 i <= 5
// 要执行 5 次:i 从 0 到 4,条件是 i < 5

int a = 1;
while (a <= 5) { Console.WriteLine(a++); }  // 5 次

int b = 0;
while (b < 5) { Console.WriteLine(b++); }   // 也是 5 次

调试技巧:用「次数 = 结束值 - 起始值(或 ±1)」验证边界。


四、适用场景与实战示例 ​

4.1 场景1:遍历集合(当需要条件控制时) ​

csharp
// 场景:遍历列表,直到找到目标元素
List<string> names = new() { "张三", "李四", "王五", "赵六" };

int index = 0;
string target = "王五";
bool found = false;

while (index < names.Count && !found)
{
    if (names[index] == target)
    {
        found = true;
        Console.WriteLine($"找到 {target},索引:{index}");
    }
    else
    {
        index++;
    }
}

if (!found) Console.WriteLine("未找到");

// 对比 for:while 更适合「条件组合」复杂的场景

4.2 场景2:等待异步操作完成 ​

csharp
// 场景:轮询等待任务完成(简化示例,实际开发用 Task/async)
bool isTaskCompleted = false;
int waitSeconds = 0;
const int timeout = 10;  // 超时时间:10 秒

Console.WriteLine("开始等待任务完成...");

while (!isTaskCompleted && waitSeconds < timeout)
{
    Thread.Sleep(1000);  // 模拟每秒检查一次
    waitSeconds++;
    Console.WriteLine($"已等待 {waitSeconds} 秒...");

    // 模拟:第 5 秒时任务完成
    if (waitSeconds == 5) isTaskCompleted = true;
}

if (isTaskCompleted)
    Console.WriteLine("任务完成!");
else
    Console.WriteLine("等待超时!");

// 输出:
// 开始等待任务完成...
// 已等待 1 秒...
// 已等待 2 秒...
// 已等待 3 秒...
// 已等待 4 秒...
// 已等待 5 秒...
// 任务完成!

4.3 场景3:重复执行业务流程 ​

csharp
// 场景:ATM 机取款,用户可多次取款直到余额不足或选择退出
decimal balance = 1000m;
bool continueTransaction = true;

while (continueTransaction && balance > 0)
{
    Console.WriteLine($"\n当前余额:{balance:C}");
    Console.Write("请输入取款金额(输入 0 退出):");

    if (!decimal.TryParse(Console.ReadLine(), out decimal amount))
    {
        Console.WriteLine("输入无效,请重新输入");
        continue;  // 跳过本次,重新循环
    }

    if (amount == 0)
    {
        continueTransaction = false;
        Console.WriteLine("感谢使用,再见!");
    }
    else if (amount > balance)
    {
        Console.WriteLine("余额不足,请重新输入");
    }
    else if (amount < 0)
    {
        Console.WriteLine("金额不能为负数");
    }
    else
    {
        balance -= amount;
        Console.WriteLine($"取款成功,剩余余额:{balance:C}");
    }
}

// 输出示例:
// 当前余额:¥1,000.00
// 请输入取款金额(输入 0 退出):500
// 取款成功,剩余余额:¥500.00
// ...

五、基础练习题 ​

练习1:输出指定序列 ​

题目:使用 while 循环输出以下序列:

2 4 8 16 32 64 128

提示:每个数字是前一个的 2 倍。

参考答案
csharp
int num = 2;
while (num <= 128)
{
    Console.Write(num + " ");
    num *= 2;  // 等价于 num = num * 2
}
Console.WriteLine();

// 输出:2 4 8 16 32 64 128

练习2:计算数字各位之和 ​

题目:输入一个正整数,计算它各位数字之和。例如输入 1234,输出 10(1+2+3+4)。

提示:用 % 10 取最后一位,用 / 10 去掉最后一位。

参考答案
csharp
Console.Write("请输入一个正整数:");
int number = int.Parse(Console.ReadLine());
int sum = 0;
int temp = number;

while (temp > 0)
{
    int digit = temp % 10;   // 取最后一位
    sum += digit;            // 累加
    temp /= 10;              // 去掉最后一位
}

Console.WriteLine($"{number} 的各位数字之和为:{sum}");

// 示例:
// 输入:1234
// 过程:temp=1234 → digit=4,sum=4,temp=123
//       temp=123  → digit=3,sum=7,temp=12
//       temp=12   → digit=2,sum=9,temp=1
//       temp=1    → digit=1,sum=10,temp=0 → 退出
// 输出:1234 的各位数字之和为:10

练习3:模拟用户登录校验 ​

题目:模拟登录系统,用户最多有 3 次输入密码的机会。密码正确显示「登录成功」,3 次都错误显示「账户锁定」。

预设密码:admin123

参考答案
csharp
const string correctPassword = "admin123";
const int maxAttempts = 3;
int attempts = 0;
bool loginSuccess = false;

while (attempts < maxAttempts && !loginSuccess)
{
    Console.Write($"请输入密码(还剩 {maxAttempts - attempts} 次机会):");
    string input = Console.ReadLine();
    attempts++;

    if (input == correctPassword)
    {
        loginSuccess = true;
        Console.WriteLine("登录成功!");
    }
    else
    {
        Console.WriteLine("密码错误!");
    }
}

if (!loginSuccess)
{
    Console.WriteLine("尝试次数过多,账户已锁定!");
}

// 输出示例:
// 请输入密码(还剩 3 次机会):123
// 密码错误!
// 请输入密码(还剩 2 次机会):456
// 密码错误!
// 请输入密码(还剩 1 次机会):admin123
// 登录成功!

六、核心知识点总结 ​

6.1 while 循环核心特征 ​

特征说明
先判断后执行条件为 false 时,循环体一次都不执行
条件驱动适合「不知道循环多少次」的场景
变量外置循环变量通常在 while 外部声明,作用域更大
灵活但危险结构简单,但容易因忘记更新变量导致死循环

6.2 while vs for 速查 ​

知道循环次数/需要索引 → for
不知道次数/条件驱动 → while
需要至少执行一次 → do-while
只读遍历集合 → foreach

6.3 安全检查清单 ​

写完 while 循环后,检查:

  • [ ] 循环变量是否已初始化?
  • [ ] 循环体内是否有变量更新?
  • [ ] 更新方向是否与条件匹配(递增用 <,递减用 >)?
  • [ ] 边界条件是否正确(用次数验证)?
  • [ ] 是否有退出机制(break/return/异常)?

结语 ​

while 循环是程序世界的「自动驾驶」——你设定一个目的地(条件),它自己控制油门和刹车(判断 + 执行)。与 for 的「固定路线」不同,while 更像「随机应变」:只要条件满足,就一直走下去。

掌握 while 的关键心法:

  • 结构上:条件在外,更新在内,先判断后执行
  • 逻辑上:确保条件最终会变为 false,break/continue 是应急出口
  • 实战上:条件驱动选 while,次数驱动选 for,至少一次选 do-while

当你下次面对「只要……就继续……」的需求时,while 循环就是你的最佳选择。