C# 零基础到精通教程 - 第四章:流程控制——让程序自己“做决定“写在前面
4.1 为什么需要流程控制?
4.1.1 现实中到处都是"选择"
text
早上起床:
如果(今天周末){
继续睡觉
}否则{
起床去上班
}
过马路:
如果(绿灯亮){
通过马路
}否则{
等待
}
4.1.2 没有流程控制的程序
csharp
// 这样的程序永远只会做同一件事
Console.WriteLine("你好");
Console.WriteLine("你好");
Console.WriteLine("你好");
// 无法根据用户输入做出不同反应
4.1.3 有流程控制的程序
csharp
Console.Write("请输入你的年龄:");
int age = Convert.ToInt32(Console.ReadLine());
if (age >= 18)
{
Console.WriteLine("欢迎进入网站!");
}
else
{
Console.WriteLine("对不起,你未成年,不能访问。");
}
4.1.4 流程控制三大结构
text
结构化程序设计三大结构 ├── 顺序结构(默认) → 代码从上往下依次执行 ├── 选择结构 → if、switch,根据条件选择执行哪段代码 └── 循环结构 → for、while、do-while,重复执行某段代码
4.2 条件判断:if 语句
4.2.1 if 的基本语法
csharp
// 语法
if (条件表达式)
{
// 条件为 true 时执行的代码
}
流程图:
text
开始
│
▼
┌─────────┐
│ 条件判断 │
└────┬────┘
│
┌───┴───┐
│ │
true false
│ │
▼ │
┌─────────┐ │
│ 执行代码 │ │
└────┬────┘ │
│ │
└───┬───┘
│
▼
结束
示例:
csharp
int score = 85;
if (score >= 60)
{
Console.WriteLine("恭喜,考试通过了!");
}
// 输出:恭喜,考试通过了!
4.2.2 if-else 语句
csharp
// 语法
if (条件表达式)
{
// 条件为 true 时执行
}
else
{
// 条件为 false 时执行
}
流程图:
text
开始
│
▼
┌─────────┐
│ 条件判断 │
└────┬────┘
│
┌───┴───┐
│ │
true false
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ 执行代码A│ │ 执行代码B│
└────┬────┘ └────┬────┘
│ │
└─────┬─────┘
│
▼
结束
示例:
csharp
int temperature = 35;
if (temperature > 30)
{
Console.WriteLine("天气太热了,开空调吧!");
}
else
{
Console.WriteLine("天气不错,出去走走!");
}
// 输出:天气太热了,开空调吧!
4.2.3 if-else if-else 多条件判断
csharp
// 语法
if (条件1)
{
// 条件1为 true 时执行
}
else if (条件2)
{
// 条件1为 false 且条件2为 true 时执行
}
else if (条件3)
{
// 条件1、2为 false 且条件3为 true 时执行
}
else
{
// 所有条件都为 false 时执行
}
示例:成绩评级
csharp
Console.Write("请输入你的分数(0-100):");
int score = Convert.ToInt32(Console.ReadLine());
if (score >= 90)
{
Console.WriteLine("评级:A(优秀)");
}
else if (score >= 80)
{
Console.WriteLine("评级:B(良好)");
}
else if (score >= 70)
{
Console.WriteLine("评级:C(中等)");
}
else if (score >= 60)
{
Console.WriteLine("评级:D(及格)");
}
else
{
Console.WriteLine("评级:F(不及格)");
}
4.2.4 嵌套 if
if 语句里面再放 if 语句
csharp
int age = 25;
bool hasID = true;
if (age >= 18)
{
if (hasID)
{
Console.WriteLine("可以进入酒吧");
}
else
{
Console.WriteLine("请出示身份证");
}
}
else
{
Console.WriteLine("未成年人禁止入内");
}
// 可以用逻辑运算符简化
if (age >= 18 && hasID)
{
Console.WriteLine("可以进入酒吧");
}
else if (age >= 18 && !hasID)
{
Console.WriteLine("请出示身份证");
}
else
{
Console.WriteLine("未成年人禁止入内");
}
4.2.5 常见陷阱:悬挂 else
csharp
// 错误示例:else 与哪个 if 匹配?
int x = 5;
if (x > 0)
if (x > 10)
Console.WriteLine("x大于10");
else
Console.WriteLine("x不大于0"); // 这个 else 匹配的是内层 if!
// 正确做法:使用大括号明确范围
if (x > 0)
{
if (x > 10)
{
Console.WriteLine("x大于10");
}
}
else
{
Console.WriteLine("x不大于0");
}
4.3 多路分支:switch 语句
4.3.1 什么时候用 switch?
当一个变量有很多种可能的取值,每种取值执行不同代码时,用 if-else 会很冗长,这时用 switch 更清晰。
if-else 版本(冗长):
csharp
int day = 3;
if (day == 1)
{
Console.WriteLine("星期一");
}
else if (day == 2)
{
Console.WriteLine("星期二");
}
else if (day == 3)
{
Console.WriteLine("星期三");
}
// ... 需要写7个判断
switch 版本(清晰):
csharp
int day = 3;
switch (day)
{
case 1:
Console.WriteLine("星期一");
break;
case 2:
Console.WriteLine("星期二");
break;
case 3:
Console.WriteLine("星期三");
break;
case 4:
Console.WriteLine("星期四");
break;
case 5:
Console.WriteLine("星期五");
break;
case 6:
Console.WriteLine("星期六");
break;
case 7:
Console.WriteLine("星期日");
break;
default:
Console.WriteLine("无效的日期");
break;
}
4.3.2 switch 语法详解
csharp
switch (表达式) // 表达式可以是 int、char、string、枚举等
{
case 值1: // 如果表达式的值等于值1
// 执行的代码
break; // 跳出 switch(必须要有,除非特殊情况)
case 值2:
// 执行的代码
break;
case 值3:
case 值4: // 多个 case 共享同一段代码
// 值3或值4都会执行这里
break;
default: // 可选,没有任何 case 匹配时执行
// 代码
break;
}
4.3.3 完整示例
csharp
using System;
Console.WriteLine("=== 菜单选择 ===");
Console.WriteLine("1. 查看余额");
Console.WriteLine("2. 存款");
Console.WriteLine("3. 取款");
Console.WriteLine("4. 退出");
Console.Write("请选择(1-4):");
string choice = Console.ReadLine();
switch (choice)
{
case "1":
Console.WriteLine("您的余额是:1000元");
break;
case "2":
Console.Write("请输入存款金额:");
double amount = Convert.ToDouble(Console.ReadLine());
Console.WriteLine($"成功存款{amount}元");
break;
case "3":
Console.Write("请输入取款金额:");
double withdraw = Convert.ToDouble(Console.ReadLine());
Console.WriteLine($"成功取款{withdraw}元");
break;
case "4":
Console.WriteLine("感谢使用,再见!");
break;
default:
Console.WriteLine("无效选择,请重新输入!");
break;
}
4.3.4 switch 新语法(C# 8.0+,开关表达式)
csharp
// 传统 switch 语句
string GetGrade(int score)
{
switch (score)
{
case >= 90:
return "A";
case >= 80:
return "B";
case >= 70:
return "C";
case >= 60:
return "D";
default:
return "F";
}
}
// 新语法:switch 表达式(更简洁)
string GetGrade2(int score) => score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
>= 60 => "D",
_ => "F" // _ 相当于 default
};
4.4 循环结构
4.4.1 为什么需要循环?
没有循环:
csharp
Console.WriteLine("第1次说:我热爱学习");
Console.WriteLine("第2次说:我热爱学习");
Console.WriteLine("第3次说:我热爱学习");
// ... 如果要写100次,代码会非常冗长
有循环:
csharp
for (int i = 1; i <= 100; i++)
{
Console.WriteLine($"第{i}次说:我热爱学习");
}
4.4.2 for 循环(最常用)
语法:
csharp
for (初始化; 条件判断; 循环变量变化)
{
// 循环体:条件为 true 时重复执行的代码
}
执行流程:
text
第1步:执行"初始化"(只执行一次) 第2步:执行"条件判断" 第3步:如果为 true → 执行循环体 → 执行"循环变量变化" → 回到第2步 第4步:如果为 false → 退出循环
流程图:
text
开始
│
▼
┌─────────┐
│ 初始化 │
└────┬────┘
│
▼
┌─────────┐
│ 条件判断 │◄────────┐
└────┬────┘ │
│ │
┌───┴───┐ │
│ │ │
true false │
│ │ │
▼ │ │
┌─────────┐ │ │
│ 循环体 │ │ │
└────┬────┘ │ │
│ │ │
▼ │ │
┌─────────┐ │ │
│ 循环变量 │ │ │
│ 变化 │──┘ │
└─────────┘ │
│
▼
结束
示例1:输出 1 到 10
csharp
for (int i = 1; i <= 10; i++)
{
Console.WriteLine(i);
}
// 输出:1 2 3 4 5 6 7 8 9 10
示例2:倒序输出 10 到 1
csharp
for (int i = 10; i >= 1; i--)
{
Console.WriteLine(i);
}
// 输出:10 9 8 7 6 5 4 3 2 1
示例3:步长不为1
csharp
// 输出偶数
for (int i = 2; i <= 10; i += 2)
{
Console.WriteLine(i);
}
// 输出:2 4 6 8 10
// 输出奇数
for (int i = 1; i <= 10; i += 2)
{
Console.WriteLine(i);
}
// 输出:1 3 5 7 9
示例4:累加求和
csharp
int sum = 0;
for (int i = 1; i <= 100; i++)
{
sum = sum + i; // 或 sum += i
}
Console.WriteLine($"1到100的和是:{sum}"); // 5050
示例5:阶乘计算
csharp
Console.Write("请输入一个正整数:");
int n = Convert.ToInt32(Console.ReadLine());
int factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i; // factorial = factorial * i
}
Console.WriteLine($"{n}! = {factorial}");
4.4.3 while 循环
当不知道循环次数,只知道"满足某个条件时继续循环"时使用
语法:
csharp
while (条件表达式)
{
// 条件为 true 时重复执行
}
示例1:猜数字游戏
csharp
Random random = new Random();
int secretNumber = random.Next(1, 101); // 1-100 随机数
int guess = 0;
int attempts = 0;
Console.WriteLine("猜猜我心里想的数字(1-100)");
while (guess != secretNumber)
{
Console.Write("请输入你的猜测:");
guess = Convert.ToInt32(Console.ReadLine());
attempts++;
if (guess > secretNumber)
{
Console.WriteLine("太大了,再试试!");
}
else if (guess < secretNumber)
{
Console.WriteLine("太小了,再试试!");
}
}
Console.WriteLine($"恭喜!你猜了{attempts}次猜中了!");
示例2:输入验证
csharp
int age = -1;
while (age < 0 || age > 150)
{
Console.Write("请输入年龄(0-150):");
age = Convert.ToInt32(Console.ReadLine());
if (age < 0 || age > 150)
{
Console.WriteLine("年龄无效,请重新输入!");
}
}
Console.WriteLine($"您的年龄是:{age}");
4.4.4 do-while 循环
至少执行一次循环体,然后再判断条件
语法:
csharp
do
{
// 循环体(至少执行一次)
} while (条件表达式);
while vs do-while:
csharp
// while:可能一次都不执行
int x = 10;
while (x < 5)
{
Console.WriteLine("while 循环"); // 不会执行
}
// do-while:至少执行一次
int y = 10;
do
{
Console.WriteLine("do-while 循环"); // 会执行一次
} while (y < 5);
实际应用:菜单循环
csharp
string choice;
do
{
Console.Clear(); // 清屏
Console.WriteLine("=== 主菜单 ===");
Console.WriteLine("1. 功能A");
Console.WriteLine("2. 功能B");
Console.WriteLine("3. 退出");
Console.Write("请选择:");
choice = Console.ReadLine();
switch (choice)
{
case "1":
Console.WriteLine("执行功能A...");
Console.WriteLine("按任意键返回菜单");
Console.ReadKey();
break;
case "2":
Console.WriteLine("执行功能B...");
Console.WriteLine("按任意键返回菜单");
Console.ReadKey();
break;
case "3":
Console.WriteLine("谢谢使用,再见!");
break;
default:
Console.WriteLine("无效选择,请重新输入!");
Console.WriteLine("按任意键继续");
Console.ReadKey();
break;
}
} while (choice != "3");
4.4.5 foreach 循环
专门用于遍历集合(数组、列表等),第五章会详细讲数组
csharp
// 预览
string[] names = { "张三", "李四", "王五" };
foreach (string name in names)
{
Console.WriteLine(name);
}
// 输出:张三 李四 王五
4.5 跳转语句
4.5.1 break——跳出循环
csharp
// 查找第一个能被7整除的数
for (int i = 1; i <= 100; i++)
{
if (i % 7 == 0)
{
Console.WriteLine($"第一个能被7整除的数是:{i}");
break; // 找到后立即退出循环
}
}
4.5.2 continue——跳过本次循环
csharp
// 输出1到10中所有的奇数(跳过偶数)
for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
continue; // 偶数跳过,不执行下面的代码
}
Console.WriteLine(i);
}
// 输出:1 3 5 7 9
4.5.3 break vs continue 对比
| 语句 | 作用 | 类比 |
|---|---|---|
break |
立即终止整个循环 | 赛跑跑到终点,不跑了 |
continue |
跳过本次,继续下一次循环 | 跳过路上的一个坑,继续跑 |
csharp
// 对比示例
Console.WriteLine("=== break 示例 ===");
for (int i = 1; i <= 5; i++)
{
if (i == 3) break;
Console.WriteLine(i);
}
// 输出:1 2
Console.WriteLine("=== continue 示例 ===");
for (int i = 1; i <= 5; i++)
{
if (i == 3) continue;
Console.WriteLine(i);
}
// 输出:1 2 4 5
4.5.4 goto——跳转到标签(不推荐)
goto 会让代码难以阅读,一般不建议使用,但了解即可
csharp
// 不推荐使用,仅作了解
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (i == 5 && j == 5)
{
goto EndLoop; // 跳出多层循环
}
}
}
EndLoop:
Console.WriteLine("跳出了多层循环");
4.6 循环嵌套
循环里面再放循环
示例1:打印矩形
csharp
int rows = 5;
int cols = 10;
for (int i = 0; i < rows; i++) // 外层循环控制行数
{
for (int j = 0; j < cols; j++) // 内层循环控制每行列数
{
Console.Write("*");
}
Console.WriteLine(); // 每行结束后换行
}
// 输出:
// **********
// **********
// **********
// **********
// **********
示例2:打印三角形
csharp
int height = 5;
for (int i = 1; i <= height; i++) // 行数
{
for (int j = 1; j <= i; j++) // 每行的星号数 = 行号
{
Console.Write("*");
}
Console.WriteLine();
}
// 输出:
// *
// **
// ***
// ****
// *****
示例3:打印九九乘法表
csharp
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= i; j++)
{
Console.Write($"{j}×{i}={i * j}\t");
}
Console.WriteLine();
}
// 输出:
// 1×1=1
// 1×2=2 2×2=4
// 1×3=3 2×3=6 3×3=9
// ...
4.7 综合示例
示例1:猜数字游戏(完整版)
csharp
using System;
Console.WriteLine("=== 猜数字游戏 ===");
Console.WriteLine("我已经想好了一个1-100之间的数字");
Console.WriteLine("你有10次机会猜中它!");
Random random = new Random();
int secretNumber = random.Next(1, 101);
int guess;
int attempts = 0;
int maxAttempts = 10;
bool guessedCorrectly = false;
while (attempts < maxAttempts && !guessedCorrectly)
{
Console.Write($"\n还剩{maxAttempts - attempts}次机会,请输入你的猜测:");
if (!int.TryParse(Console.ReadLine(), out guess))
{
Console.WriteLine("请输入有效的数字!");
continue;
}
attempts++;
if (guess == secretNumber)
{
guessedCorrectly = true;
Console.WriteLine($"\n🎉 恭喜!你用了{attempts}次猜中了数字{secretNumber}!");
}
else if (guess < secretNumber)
{
Console.WriteLine("太小了,再试试更大的数字!");
}
else
{
Console.WriteLine("太大了,再试试更小的数字!");
}
}
if (!guessedCorrectly)
{
Console.WriteLine($"\n😭 很遗憾,机会用完了!正确答案是:{secretNumber}");
}
示例2:学生成绩统计系统
csharp
using System;
Console.WriteLine("=== 学生成绩统计系统 ===");
Console.Write("请输入班级人数:");
int studentCount = Convert.ToInt32(Console.ReadLine());
double sum = 0;
int maxScore = int.MinValue;
int minScore = int.MaxValue;
int passCount = 0;
int failCount = 0;
for (int i = 1; i <= studentCount; i++)
{
Console.Write($"请输入第{i}个学生的成绩:");
int score = Convert.ToInt32(Console.ReadLine());
sum += score;
if (score > maxScore) maxScore = score;
if (score < minScore) minScore = score;
if (score >= 60)
passCount++;
else
failCount++;
}
double average = sum / studentCount;
Console.WriteLine("\n=== 统计结果 ===");
Console.WriteLine($"总人数:{studentCount}");
Console.WriteLine($"总分:{sum}");
Console.WriteLine($"平均分:{average:F2}");
Console.WriteLine($"最高分:{maxScore}");
Console.WriteLine($"最低分:{minScore}");
Console.WriteLine($"及格人数:{passCount},及格率:{(double)passCount / studentCount * 100:F1}%");
Console.WriteLine($"不及格人数:{failCount},不及格率:{(double)failCount / studentCount * 100:F1}%");
// 评级分布
int aCount = 0, bCount = 0, cCount = 0, dCount = 0, fCount = 0;
// 这里需要重新输入一遍成绩,或者用数组存储(第五章)
示例3:ATM 模拟系统
csharp
using System;
double balance = 1000; // 初始余额
bool isRunning = true;
Console.WriteLine("=== ATM 模拟系统 ===");
while (isRunning)
{
Console.WriteLine("\n请选择操作:");
Console.WriteLine("1. 查询余额");
Console.WriteLine("2. 存款");
Console.WriteLine("3. 取款");
Console.WriteLine("4. 退出");
Console.Write("请输入选项:");
string choice = Console.ReadLine();
switch (choice)
{
case "1":
Console.WriteLine($"当前余额:{balance:C}"); // :C 货币格式
break;
case "2":
Console.Write("请输入存款金额:");
if (double.TryParse(Console.ReadLine(), out double depositAmount) && depositAmount > 0)
{
balance += depositAmount;
Console.WriteLine($"存款成功!当前余额:{balance:C}");
}
else
{
Console.WriteLine("无效金额!");
}
break;
case "3":
Console.Write("请输入取款金额:");
if (double.TryParse(Console.ReadLine(), out double withdrawAmount) && withdrawAmount > 0)
{
if (withdrawAmount <= balance)
{
balance -= withdrawAmount;
Console.WriteLine($"取款成功!当前余额:{balance:C}");
}
else
{
Console.WriteLine("余额不足!");
}
}
else
{
Console.WriteLine("无效金额!");
}
break;
case "4":
isRunning = false;
Console.WriteLine("感谢使用,再见!");
break;
default:
Console.WriteLine("无效选项,请重新选择!");
break;
}
}
4.8 常见错误与陷阱
错误1:死循环
csharp
// ❌ 错误:条件永远为 true
int i = 0;
while (i < 10)
{
Console.WriteLine(i);
// 忘记写 i++
}
// ❌ 错误:分号位置错误
for (int i = 0; i < 10; i++); // 多了一个分号,循环体为空
{
Console.WriteLine(i); // 只执行一次,且 i 不可见
}
错误2:if 后面多分号
csharp
int x = 10;
if (x > 5); // 多了一个分号,if 语句结束了
{
Console.WriteLine("x大于5"); // 这个代码块总是执行
}
错误3:switch 忘记 break
csharp
int day = 2;
switch (day)
{
case 1:
Console.WriteLine("周一");
// 忘记 break,会"穿透"到下一个 case
case 2:
Console.WriteLine("周二");
break;
}
// 输出:周一 周二(不是预期的结果)
错误4:浮点数作为循环条件
csharp
// ❌ 浮点数不精确,可能导致多一次或少一次循环
for (double d = 0.0; d != 1.0; d += 0.1)
{
Console.WriteLine(d); // 永远不会到 1.0,死循环
}
// ✅ 使用整数控制循环
for (int i = 0; i <= 10; i++)
{
double d = i * 0.1;
}
错误5:赋值 vs 比较
csharp
int x = 5;
if (x = 10) // 赋值,不是比较,编译错误
{
// ...
}
if (x == 10) // ✅ 正确
4.9 本章总结
核心知识点导图
text
流程控制
├── 选择结构
│ ├── if
│ ├── if-else
│ ├── if-else if-else
│ ├── 嵌套if
│ └── switch-case
│
├── 循环结构
│ ├── for(确定次数)
│ ├── while(不确定次数,先判断)
│ ├── do-while(至少执行一次)
│ └── foreach(遍历集合)
│
└── 跳转语句
├── break(跳出循环)
├── continue(跳过本次)
└── goto(不推荐)
选择哪种循环?
| 场景 | 推荐循环 |
|---|---|
| 知道确切循环次数 | for |
| 不知道次数,知道继续条件 | while |
| 至少需要执行一次 | do-while |
| 遍历数组/集合 | foreach |
4.10 练习题
基础题
-
用
if-else写一个程序,判断用户输入的数字是正数、负数还是零。 -
用
switch写一个程序,输入数字1-7,输出对应的星期几(1=周一...7=周日)。 -
用
for循环输出 1 到 100 中所有 3 的倍数。 -
用
while循环计算 1 到 100 的累加和。
应用题
-
打印如下图案(输入行数 n):
text
* ** *** **** *****
-
打印如下图案(输入行数 n):
text
* *** ***** *******
-
写一个程序,判断输入的数字是否是质数。
-
写一个程序,输出斐波那契数列的前 n 项(0, 1, 1, 2, 3, 5, 8, 13...)。
挑战题
-
写一个"数字反转"程序:
-
输入:12345
-
输出:54321
-
提示:用
% 10获取最后一位,用/ 10去掉最后一位
-
-
写一个"水仙花数"查找程序:
-
水仙花数:各位数字的立方和等于本身
-
例如:153 = 1³ + 5³ + 3³
-
找出所有的三位数水仙花数
-
-
用循环嵌套实现一个"万年历日历"输出(输入年份和月份,输出该月的日历表)。
-
写一个"简易银行系统":
-
支持开户(存钱)
-
支持存款、取款
-
支持转账
-
支持查询余额
-
使用循环菜单 + switch
-
更多推荐
所有评论(0)