C#基础教程[2] 循环程序设计
之前学的程序里的语句都只能执行最多一次, 无法发挥出计算机的优势. 而为了让代码中的一行语句可以被执行若干遍, 于是便有了循环.
循环语句
while
循环
假设我们要写一个程序永远不停的输出 hello world
(直到你关掉这个程序), 代码如下:
1 | while (true) { |
其中小括号里的为条件, 大括号里的(即这个代码块)为参与循环的部分
在进入循环之前会先判断括号里的条件,如果为 true
才执行,每次执行完大括号里的内容会再次判断括号里的条件,如果为 true
则再次执行大括号里的内容,循环往复直到括号里的条件为 false
因为上面的例子中括号里恒为 true
所以这个循环会永远进行下去
不能写成 while(1)
, 当你了解了 C#
中的数据类型转换机制的时候你会对此有更深的感悟
再举一个不是死循环的例子:
1 | int a = 5; |
大家可以预测一下输出的结果。
点我查看输出结果
1 | a 的值: 5 |
猜数游戏
在这里先介绍一下如何生成随机数:
1 | Random rd = new Random(); // 如果要生成多组随机数 这行也只需要在最开始写一遍 |
这么写具体的原理会在下一节进行解释
如果要生成指定范围内的随机数应该写为:
1 | rd.Next(5, 11); // 左闭右开,所以此处为 [5,11) 范围内的随机数,并不包括 11 |
这样我们就可以写一个猜数游戏了:生成 [1,100] 内的一个随机数,让玩家来猜这个数的大小,提示玩家猜测的数是偏大还是偏小,直到玩家猜中
代码:
1 | Random rd = new Random(); |
例题 2-1 竞选社长
假设电子电路社要竞选下一届社长,有两名候选人分别是A和B,社团每名同学必须并且只能投一票,最终得票多的人为社长.
输入包含若干行的字符,每行仅包含A或B,输入以字符0结束。(原题为一行字符序列)
1 | string str = Console.ReadLine(); |
for
循环
以下代码列是一个简单的 for
语句,它循环遍历其代码块(即被大括号括起来的内容)十次,并打印 i
的当前值。
1 | for (int i=0; i < 10; i++) { |
大括号包起来的代码块部分很好理解,让我们来看看小括号里的内容:
小括号里被分号 ;
分为三个部分,分别表示:
- 在进入循环语句和判断条件之前执行的语句,无论循环是否执行这个语句都只会被执行一次
- 循环判断的条件,与
while
语句同理 - 每次执行完大括号里的内容之后执行的语句,注意是在执行完该语句之后才会再次判断条件
刚刚的学习 while
循环时展示的代码可以用 for
循环更简单的写出来:
1 | for (int a=5; a < 10; a++) { |
再对比刚刚的代码看:
1 | int a = 5; // 被小括号里的第一部分代替 |
注意小括号里第一部分写为 int a
和在循环外写 int a
的区别:
1 | for (int a=5; a < 10; a++) { |
换句话说在括号里定义的 a
就只会在循环的范围内生效
如果想使用 a 的值请像下面这么写:
1 | int a; |
也请注意最后 a
的值为 10 而不是 9。考虑反证法,如果 a 为 9 则还满足循环的条件,则会继续执行循环的内容,所以 a 一定不是 9
例题 2-2 FizzBuzz 问题
每行输出一个数字 从 1 到 100,满足以下规则:
- 如果当前值可被 3 整除,则在该数字旁打印 Fizz。
- 如果当前值可被 5 整除,则在该数字旁打印 Buzz。
- 如果当前值可 同时 被 3 和 5 整除,则在该数字旁打印 FizzBuzz。
例如:
1 | 1 |
示例程序:
1 | // 注意这里用的是 <= , 如果想模仿上面的例子使用 <, 请把100 改为 101 |
无代码注释版:
1 | for(int i=1; i <= 100; i++) { |
请注意括号里三个部分不同就会导致循环不同的结果:(注释为循环时 i
的范围)
1 | for (int i=1; i <= 10; i++) { } // [1,10] |
嵌套循环
循环是可以嵌套的,当出现嵌套循环的时候,先执行内层循环,内层循环执行完一遍之后再回到外层的循环,再从外层循环进入内层循环,类似数学中的 ,又类似平常说的“先从上到下 再从左到右”也可以理解为嵌套循环。让我们看一个例子:
1 | for(int i=5; i < 10; i++) { |
请注意在嵌套循环的时候两个变量 i
和 j
不要错写成一样的,会引起混淆,就像一个班里有两个人都叫小明的时候你直接喊“小明”会不知道你指的是谁。
输出
1 | i 的值: 5 |
例题 2-3 等腰直角三角形
KiKi学习了循环,BoBo老师给他出了一系列打印图案的练习,该任务是打印用“*”组成的翻转直角三角形图案。(原题为多组数据,这里简化为一组)
输入一个数字即等腰直角三角形的侧边长,当输入为 5 时输出如下:
1 | * * * * * |
示例代码:
1 | int n = Convert.ToInt32(Console.ReadLine()); |
循环控制语句
以下内容对 for
和 while
均适用
break
语句
break
表示终止循环,当在循环里遇到 break
语句时,循环会立即终止,且程序流将继续执行紧接着循环语句之后的语句。例如:
1 | for(int i=5; i < 10; i++) { |
输出
1 | i 的值: 5 |
当 break
语句用在嵌套循环中,只会跳出最内层的循环,例如:
1 | for (int i = 5; i < 10; i++) { |
输出
1 | i 的值: 5 |
continue
语句
continue
语句与 break
语句类似,但 continue
语句的意思是 停止当前循环体里语句的执行,跳到循环的开始,(对于 for
循环)执行括号里第三部分的语句,然后重新判断循环条件决定是否继续循环。
例如把上面的例子中的 break
改成 continue
:
1 | for(int i=5; i < 10; i++) { |
输出
1 | i 的值: 5 |
注意这里跳过了 i = 8
时的情况直接输出了 i = 9
的情况
练习
2-1 阶乘 (P5739)
输入 n
, 输出 n
的阶乘(n <= 12)
2-2 aabb
输出所有形如 aabb 的完全平方数
2-3 最高分与最低分之差
第一行输入一个数 n, 然后n行每行一个整数代表一个人的成绩, 求出最高分和最低分的差值
5
98
100
99
97
95
5
2-4 RPG游戏
在大部分角色扮演游戏中,玩家角色会与NPC战斗。在此练习中,我们归纳出战斗过程的本质。 英雄和怪物在开始时的生命值相同。 在英雄攻击时,它们将生成一个随机值,该值将从怪物的生命值中减去。 如果怪物的生命值大于零,则会轮到它们攻击英雄。 只要英雄和怪物的生命值都大于零,战斗就会继续进行。
为游戏实现以下规则:
游戏规则
- 英雄和怪物在开始时的生命值为 10。
- 所有攻击都是介于 1 到 10 之间的随机值。
- 英雄首先攻击。
- 输出怪物损失的生命值,以及剩余的生命值。
- 如果怪物的生命值大于 0,则它会攻击英雄。
- 输出英雄损失的生命值,以及剩余的生命值。
- 继续此攻击顺序,直到怪物或英雄任意一方的生命值为零或更低。
- 输出胜利者。