09-循环语句
循环语句用于重复执行一段代码,直到满足特定条件。C# 提供了四种循环机制,每种适用于不同场景。
一、四种循环对比总览
| 循环类型 | 执行特点 | 最少执行次数 | 适用场景 |
|---|---|---|---|
while | 先判断条件,后执行循环体 | 0 次 | 不确定循环次数,可能一次都不执行 |
do-while | 先执行循环体,后判断条件 | 1 次 | 至少需要执行一次循环体 |
for | 初始化、条件、迭代集中在头部 | 0 次 | 明确知道循环次数 |
foreach | 自动遍历集合元素 | 0 次 | 遍历数组或集合全部元素 |
二、while 循环
基本语法
csharp
while (条件表达式)
{
// 循环体——条件为 true 时重复执行
}执行流程: 先判断条件 → 为 true 则执行循环体 → 再次判断条件 → 直到条件为 false 退出。
示例:数字累加
csharp
// 计算 1+2+3+...+100
int i = 1;
int sum = 0;
while (i <= 100)
{
sum += i; // 等价于 sum = sum + i
i++; // 计数器递增——必须有改变条件的语句
}
Console.WriteLine($"1+2+...+100 = {sum}"); // 输出:5050示例:猜数字游戏
csharp
Random rnd = new Random();
int target = rnd.Next(1, 101); // 生成 1~100 的随机数
int guess = 0;
int attempts = 0;
Console.WriteLine("猜一个 1~100 之间的数字:");
while (guess != target)
{
guess = int.Parse(Console.ReadLine());
attempts++;
if (guess > target)
Console.WriteLine("太大了,再试试!");
else if (guess < target)
Console.WriteLine("太小了,再试试!");
}
Console.WriteLine($"恭喜你猜对了!答案是 {target},共猜了 {attempts} 次。");注意事项
| 问题 | 说明 | 示例 |
|---|---|---|
| 死循环 | 条件永远为 true,循环永不结束 | while (true) { } |
| 忘记递增 | 循环变量未改变,导致死循环 | while (i < 10) { } 但 i 从不增加 |
| 条件不满足 | 条件一开始就为 false,循环体一次也不执行 | while (false) { } |
三、do-while 循环
基本语法
csharp
do
{
// 循环体——至少执行一次
} while (条件表达式); // 注意:末尾有分号与 while 的核心区别
csharp
// while:可能一次都不执行
int a = 10;
while (a < 5)
{
Console.WriteLine("这行不会输出");
}
// do-while:至少执行一次
int b = 10;
do
{
Console.WriteLine("这行会输出一次");
} while (b < 5);示例:菜单选择
csharp
string choice;
do
{
Console.WriteLine("=== 菜单 ===");
Console.WriteLine("1. 查询余额");
Console.WriteLine("2. 取款");
Console.WriteLine("3. 存款");
Console.WriteLine("0. 退出");
Console.Write("请选择:");
choice = Console.ReadLine();
switch (choice)
{
case "1":
Console.WriteLine("您的余额为:1000 元");
break;
case "2":
Console.WriteLine("请输入取款金额");
break;
case "3":
Console.WriteLine("请输入存款金额");
break;
}
Console.WriteLine(); // 空行
} while (choice != "0"); // 选择 0 时退出
Console.WriteLine("感谢使用,再见!");四、for 循环
基本语法与执行顺序
csharp
for (初始化表达式; 条件表达式; 迭代表达式)
{
// 循环体
}执行顺序:
步骤1: 初始化表达式(仅执行一次)
↓
步骤2: 条件表达式(true 则继续,false 则退出)
↓
步骤3: 执行循环体
↓
步骤4: 迭代表达式
↓
回到步骤2示例:遍历数组求和
csharp
int[] scores = { 85, 92, 78, 95, 88 };
int sum = 0;
for (int i = 0; i < scores.Length; i++)
{
sum += scores[i];
}
double average = (double)sum / scores.Length;
Console.WriteLine($"总分:{sum},平均分:{average:F1}"); // 输出:总分:438,平均分:87.6多种变体
csharp
// 1. 多个变量同时控制
for (int i = 1, j = 10; i < j; i++, j--)
{
Console.WriteLine($"i={i}, j={j}");
}
// 2. 省略初始化
int k = 0;
for (; k < 5; k++)
{
Console.WriteLine(k);
}
// 3. 省略所有表达式(死循环)
// for (;;) { }
// 4. 循环变量在外部使用
int m;
for (m = 0; m < 10; m++) { }
Console.WriteLine($"最终值:{m}"); // 输出:10实战:打印乘法表
csharp
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= i; j++)
{
Console.Write($"{j}×{i}={i * j,-4}"); // -4 表示左对齐占4位
}
Console.WriteLine();
}五、foreach 循环
用于遍历实现了 IEnumerable 接口的集合(数组、List、Dictionary 等)。
基本语法
csharp
foreach (元素类型 变量名 in 集合)
{
// 使用变量
}示例:遍历不同集合
csharp
// 遍历数组
int[] numbers = { 10, 20, 30 };
foreach (int n in numbers)
Console.WriteLine(n);
// 遍历 List
List<string> names = new List<string> { "张三", "李四", "王五" };
foreach (string name in names)
Console.WriteLine(name);
// 遍历 Dictionary
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "语文", 90 }, { "数学", 85 }, { "英语", 88 }
};
foreach (KeyValuePair<string, int> kvp in scores)
{
Console.WriteLine($"{kvp.Key}:{kvp.Value}分");
}
// 只遍历键或值
foreach (string key in scores.Keys) Console.WriteLine(key);
foreach (int value in scores.Values) Console.WriteLine(value);foreach 的限制
csharp
// 限制1:迭代变量是只读的,不能修改
int[] arr = { 1, 2, 3 };
foreach (int n in arr)
{
// n = 10; // 编译错误:无法对 foreach 变量赋值
}
// 限制2:遍历时不能修改集合(增删元素)
List<int> list = new List<int> { 1, 2, 3 };
foreach (int n in list)
{
// list.Add(4); // 运行错误:InvalidOperationException
// list.Remove(n); // 同样会抛出异常
}
// 如果需要修改,使用 for 循环
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] % 2 == 0)
list.RemoveAt(i);
}六、循环控制语句
| 控制语句 | 作用 | 适用场景 |
|---|---|---|
break | 立即终止整个循环 | 找到目标后提前结束 |
continue | 跳过本次循环剩余部分,进入下一次迭代 | 排除某些特殊情况 |
return | 退出整个方法(不仅仅是循环) | 需要直接结束方法 |
goto | 跳转到指定标签 | 多层嵌套循环中快速跳出(慎用) |
break:提前退出
csharp
// 查找第一个偶数
int[] numbers = { 3, 5, 2, 7, 8 };
for (int i = 0; i < numbers.Length; i++)
{
if (numbers[i] % 2 == 0)
{
Console.WriteLine($"找到第一个偶数:{numbers[i]},索引:{i}");
break; // 找到后立即退出循环
}
}
// 输出:找到第一个偶数:2,索引:2continue:跳过本次
csharp
// 打印 1~10 之间的奇数
for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
continue; // 偶数跳过,不打印
Console.Write($"{i} ");
}
// 输出:1 3 5 7 9break 与 continue 对比
csharp
for (int i = 1; i <= 5; i++)
{
if (i == 3)
break; // i=3 时整个循环结束
Console.Write(i + " ");
}
// break 输出:1 2
for (int i = 1; i <= 5; i++)
{
if (i == 3)
continue; // i=3 时跳过,继续下一次
Console.Write(i + " ");
}
// continue 输出:1 2 4 5goto:跳出多层嵌套
csharp
// 在二维数组中查找指定值
int[,] matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
int target = 5;
bool found = false;
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
if (matrix[i, j] == target)
{
Console.WriteLine($"找到 {target} 在 [{i},{j}]");
goto Found; // 直接跳转到标签
}
}
}
Console.WriteLine("未找到");
Found:
Console.WriteLine("查找结束");七、嵌套循环
语法理解
外层循环每执行一次,内层循环完整执行一轮。
csharp
// 理解嵌套执行流程
for (int i = 1; i <= 3; i++)
{
Console.WriteLine($"外层 i={i} —— 进入内层循环");
for (int j = 1; j <= 3; j++)
{
Console.WriteLine($" 内层 j={j}");
}
Console.WriteLine($"外层 i={i} —— 内层循环结束");
}
// 外层执行 3 次,内层执行 3×3=9 次实战:打印图形
csharp
// 直角三角形
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= i; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
// 输出:
// *
// **
// ***
// ****
// *****
// 菱形
int n = 5;
for (int i = 1; i <= n; i++)
{
for (int j = i; j < n; j++) Console.Write(" ");
for (int j = 1; j <= 2 * i - 1; j++) Console.Write("*");
Console.WriteLine();
}
for (int i = n - 1; i >= 1; i--)
{
for (int j = n; j > i; j--) Console.Write(" ");
for (int j = 1; j <= 2 * i - 1; j++) Console.Write("*");
Console.WriteLine();
}八、死循环与正确退出方式
某些场景(如服务器监听、游戏主循环)需要死循环,配合 break 或条件退出。
csharp
// 聊天程序:输入 exit 退出
while (true)
{
Console.Write("请输入消息(输入 exit 退出):");
string input = Console.ReadLine();
if (input == "exit")
{
Console.WriteLine("再见!");
break; // 退出循环
}
if (string.IsNullOrWhiteSpace(input))
{
Console.WriteLine("输入不能为空,请重新输入");
continue; // 跳过本次,回到循环开头
}
Console.WriteLine($"你发送了:{input}");
}九、综合案例
学生成绩管理系统
csharp
static void Main()
{
List<int> scores = new List<int>();
while (true)
{
Console.WriteLine("\n=== 学生成绩管理系统 ===");
Console.WriteLine("1. 添加成绩");
Console.WriteLine("2. 查看所有成绩");
Console.WriteLine("3. 统计信息");
Console.WriteLine("4. 查找成绩");
Console.WriteLine("0. 退出");
Console.Write("请选择:");
string choice = Console.ReadLine();
switch (choice)
{
case "1":
Console.Write("请输入成绩(0-100):");
if (int.TryParse(Console.ReadLine(), out int score) && score >= 0 && score <= 100)
{
scores.Add(score);
Console.WriteLine("添加成功!");
}
else
{
Console.WriteLine("输入无效!");
}
break;
case "2":
Console.WriteLine($"共 {scores.Count} 个成绩:");
for (int i = 0; i < scores.Count; i++)
Console.WriteLine($" [{i}] {scores[i]}");
break;
case "3":
if (scores.Count > 0)
{
int sum = 0, max = scores[0], min = scores[0];
foreach (int s in scores)
{
sum += s;
if (s > max) max = s;
if (s < min) min = s;
}
Console.WriteLine($"平均分:{(double)sum / scores.Count:F1}");
Console.WriteLine($"最高分:{max}");
Console.WriteLine($"最低分:{min}");
}
else
{
Console.WriteLine("暂无成绩数据");
}
break;
case "4":
Console.Write("请输入要查找的分数:");
if (int.TryParse(Console.ReadLine(), out int target))
{
bool found = false;
for (int i = 0; i < scores.Count; i++)
{
if (scores[i] == target)
{
Console.WriteLine($"在索引 [{i}] 处找到");
found = true;
}
}
if (!found) Console.WriteLine("未找到该成绩");
}
break;
case "0":
Console.WriteLine("感谢使用!");
return; // 退出 Main 方法
default:
Console.WriteLine("无效选项,请重新选择");
break;
}
}
}核心知识点总结
| 循环类型 | 语法特点 | 计数方式 | 典型应用 |
|---|---|---|---|
while | 条件前置 | 外部计数器 | 不确定次数的循环 |
do-while | 条件后置(至少一次) | 外部计数器 | 菜单选择、输入验证 |
for | 初始化/条件/迭代集中 | 内置计数器 | 确定次数的循环、数组遍历 |
foreach | 自动迭代 | 无需计数器 | 遍历集合全部元素 |
注意事项
- 避免死循环:确保循环条件最终会变为
false - 循环变量作用域:
for中声明的变量只在循环内有效 - 修改集合:
foreach中不能修改集合(增删元素),用for代替 - 性能考虑:将不需要重复计算的表达式移到循环外部csharp
// 不推荐 for (int i = 0; i < list.Count; i++) // 每次循环都计算 Count // 推荐 for (int i = 0, count = list.Count; i < count; i++) // Count 只计算一次 - break vs continue vs return:
break:退出当前循环continue:跳过本次循环剩余代码return:退出整个方法


