C语言小课堂:while循环

今天,我们要一起探索C语言中一个非常基础但又极其强大的“魔法咒语”——while 语句。它能让你的程序重复执行某些任务,大大提高效率,简直是编程世界的“时间机器”!

  1. while语句是什么?

想象一下,你正在玩一个游戏,需要反复攻击同一个敌人直到它血量归零。或者,你正在编写一个程序,需要反复读取用户的输入直到用户输入“quit”。这时候,你就需要一个能让程序“循环”执行特定代码块的结构,而while语句就是C语言中实现这种“循环”的利器之一。

while 语句 ,在C语言中,是一种入口条件循环(Entry-Controlled Loop)。这意味着,在每次循环迭代之前,它都会先检查一个条件表达式。只有当这个条件表达式为真(非零)时,循环体内的代码才会被执行。如果条件为假(零),循环就会立即终止。

它的基本语法结构是这样的:

while (条件表达式) {
// 循环体:当条件为真时,会重复执行这里的代码
}

while: 关键字,表示这是一个while循环。

条件表达式: 这是一个能够产生布尔值(真或假)的表达式。它可以是任何合法的C语言表达式,例如关系表达式(a > b )、逻辑表达式(a && b)、甚至是一个变量(非零即真,零即假)。

{}: 花括号,表示循环体。当条件表达式为真时,花括号内的所有语句都会被执行。如果循环体只有一条语句,花括号可以省略,但为了代码的可读性和避免潜在错误,强烈建议总是使用花括号。

  1. while语句何时用?

什么时候用?

当你不确定循环需要执行多少次时: 这是 while循环最常见的应用场景。比如,你需要用户反复输入一个数字,直到输入一个特定值(如-1)才停止。或者你需要读取文件直到文件末尾。这些情况下,你事先并不知道循环会执行多少次。

需要根据特定条件重复执行任务时: 只要某个条件满足,就一直执行下去。例如,计算一个数的阶乘,只要数字大于1就一直乘下去。

需要实现“等待”或“监听”逻辑时: 比如在一个嵌入式系统中,等待某个传感器信号达到特定值。

为什么用?

提高代码复用性: 避免重复编写相同的代码,让程序更简洁、更易于维护。

实现复杂逻辑: 很多算法和程序都需要循环结构来处理重复性任务。

处理不确定次数的迭代: while循环在迭代次数未知时表现出色。

与关联知识点的联系和区别:

区别: do-while 循环是出口条件循环(Exit-Controlled Loop)。它会先执行一次循环体,然后再检查条件。这意味着do-while循环至少会执行一次,而while循环在条件一开始就不满足时,可能一次都不会执行。

联系: 两种循环都用于重复执行代码,但适用于不同的场景。

举例:

whilewhile (input != 'q') { ... } (如果第一次输入就是’q’,则不执行循环体)

do-whiledo { ... } while (input != 'q'); (无论如何,先让用户输入一次)

区别: for循环通常用于已知循环次数或者循环变量有明确的初始化、条件和步进规律的场景。它的结构更紧凑,将循环控制变量的初始化、循环条件和更新都放在一行。

联系: 任何 for循环都可以改写成while循环,反之亦然。但选择哪种循环取决于你的具体需求和代码可读性。如果循环次数已知或有明确的计数器,for循环通常更优;如果循环条件更基于某个状态而非计数,while 循环则更适合。

举例:

for 循环:for (int i = 0; i < 10; i++) { ... } (打印10次)

while 循环:int i = 0; while (i < 10) { ...; i++; } (同样打印10次)

for 循环:

do-while 循环:

  1. while语句怎么用?

让我们通过几个实际的编程场景来感受while循环的魅力!

场景一:简单的计数器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main() {
int count = 1; // 初始化计数器
printf("开始倒数!\n");

// 当count小于等于5时,循环执行
while (count <= 5) {
printf("当前数字:%d\n", count);
count++; // 每次循环后,计数器加1,避免死循环
}

printf("倒数结束!\n");
return 0;
}

运行结果:

开始倒数!
当前数字:1
当前数字:2
当前数字:3
当前数字:4
当前数字:5
倒数结束!

解析: 初始 count 为1,满足count <= 5,执行 printfcount++count变为2,继续满足条件,直到 count变为6,条件count <= 5不满足,循环终止。

场景二:用户输入验证(直到输入有效值为止)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main() {
int age;
printf("请输入你的年龄(1-120之间):\n");

// 只要年龄不在有效范围内,就一直循环要求输入
while (scanf("%d", &age) != 1 || age < 1 || age > 120) {
// scanf("%d", &age) != 1 表示输入不是一个整数
// age < 1 || age > 120 表示年龄不在有效范围
printf("输入无效,请重新输入你的年龄(1-120之间):\n");
// 清空输入缓冲区,避免无限循环读取错误输入
while (getchar() != '\n' && getchar() != EOF);
}

printf("你的年龄是:%d岁。输入有效!\n", age);
return 0;
}

解析: 这个例子展示了 while循环在输入验证中的强大作用。只要用户输入的值不满足条件,就会一直提示重新输入,直到输入有效值为止。scanf的返回值判断和缓冲区清空是处理用户输入时常见的技巧。

场景三:猜数字游戏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h> // 用于rand()和srand()
#include <time.h> // 用于time()

int main() {
srand(time(NULL)); // 使用当前时间作为随机数种子
int target_number = rand() % 100 + 1; // 生成1到100之间的随机数
int guess;
int attempts = 0;

printf("欢迎来到猜数字游戏!\n");
printf("我已经想好了一个1到100之间的数字,你来猜猜看吧!\n");

// 只要猜的数字不等于目标数字,就一直循环
while (guess != target_number) {
printf("请输入你的猜测:");
scanf("%d", &guess);
attempts++; // 尝试次数加1

if (guess > target_number) {
printf("太大了!\n");
} else if (guess < target_number) {
printf("太小了!\n");
} else {
printf("恭喜你,猜对了!\n");
printf("你一共猜了 %d 次。\n", attempts);
}
}

return 0;
}

解析: 这是一个经典的猜数字游戏。while循环在这里控制了游戏的进程,只要玩家没有猜对,游戏就会一直进行下去。这完美体现了while循环在“不确定执行次数”场景下的应用。

通过这几个例子,相信你对 while语句的“是什么”、“何时用”和“怎么用”有了更深刻的理解。记住,循环是编程中非常重要的概念,熟练掌握它们将大大提升你的编程能力!

📝 配套习题

  1. 选择题

以下哪个选项是关于 while循环的正确描述?

A. while 循环至少执行一次循环体。

B. while循环在执行循环体之前会检查条件表达式。

C. while循环通常用于已知循环次数的场景。

D. while循环的条件表达式必须是一个布尔常量。

  1. 判断题

while循环的条件表达式如果一开始就为假(0),那么循环体内的代码将不会被执行。

A. 正确

B. 错误

  1. 填空题

使用 while循环打印从10到1(包含1)的所有整数,并在每个数字后换行。

#include <stdio.h>
int main() {
int num = 10;
while (num ____ 1) {
printf("%d\n", num);
num____;
}
return 0;
}

  1. 编程题:计算斐波那契数列

编写一个C程序,使用 while循环计算并打印斐波那契数列的前N项。斐波那契数列的定义是:F(0)=0, F(1)=1, F(n) = F(n-1) + F(n-2) (n ≥ 2)。程序应提示用户输入N。

示例输入:5

示例输出:斐波那契数列前5项是: 0 1 1 2 3

  1. 编程题:数字反转

编写一个C程序,使用 while循环将一个正整数的各位数字反转。例如,输入12345,输出54321。

示例输入:12345

示例输出:反转后的数字是: 54321

💡 习题讲解

  1. 选择题

以下哪个选项是关于 while循环的正确描述?

A. while 循环至少执行一次循环体。

B. while循环在执行循环体之前会检查条件表达式。

C. while循环通常用于已知循环次数的场景。

D. while循环的条件表达式必须是一个布尔常量。

答案:B

解析:

A选项错误: while循环是入口条件循环,如果条件表达式一开始就为假,循环体将一次都不会执行。do-while循环才至少执行一次。

B选项正确: 这是 while循环的定义特征,它先判断条件,条件为真才进入循环体。

C选项错误: while循环更常用于循环次数不确定的场景,而for循环通常用于已知循环次数的场景。

D选项错误: while循环的条件表达式可以是任何能产生非零(真)或零(假)值的表达式,例如关系表达式、逻辑表达式或变量,不限于布尔常量。

  1. 判断题

while循环的条件表达式如果一开始就为假(0),那么循环体内的代码将不会被执行。

A. 正确

B. 错误

答案:A

解析: 这是 while循环作为“入口条件循环”的核心特性。它在进入循环体之前会先进行条件判断。如果条件不满足,那么循环体内的代码就不会被执行。

  1. 填空题

使用 while循环打印从10到1(包含1)的所有整数,并在每个数字后换行。

#include <stdio.h>
int main() {
int num = 10;
while (num ____ 1) {
printf("%d\n", num);
num____;
}
return 0;
}

答案:

#include <stdio.h>
int main() {
int num = 10;
while (num >= 1) { // 条件表达式:只要num大于等于1,就继续循环
printf("%d\n", num);
num--; // 每次循环后,num自减1,向1递减
}
return 0;
}

解析:

num >= 1 : 循环的目的是从10打印到1。所以,只要num的值大于或等于1,我们就应该继续打印。当num变为0时,条件0 >= 1 为假,循环终止。

num-- : 为了让 num从10递减到1,每次循环后,我们需要将num的值减1。这是避免死循环的关键,确保num最终能达到循环终止的条件。

  1. 编程题:计算斐波那契数列

编写一个C程序,使用 while循环计算并打印斐波那契数列的前N项。斐波那契数列的定义是:F(0)=0, F(1)=1, F(n) = F(n-1) + F(n-2) (n ≥ 2)。程序应提示用户输入N。

示例输入:5

示例输出:斐波那契数列前5项是: 0 1 1 2 3

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>

int main() {
int n, i = 0;
long long t1 = 0, t2 = 1, nextTerm; // 使用long long防止溢出,特别是n较大时

printf("请输入要打印的斐波那契数列项数 (N): ");
scanf("%d", &n);

printf("斐波那契数列前%d项是:\n", n);

// 特殊处理N为0或1的情况
if (n == 0) {
printf("没有项。\n");
return 0;
}
if (n == 1) {
printf("%lld ", t1);
return 0;
}

// 当i小于n时,循环执行
while (i < n) {
printf("%lld ", t1); // 打印当前项
nextTerm = t1 + t2; // 计算下一项
t1 = t2; // 更新t1为旧的t2
t2 = nextTerm; // 更新t2为新计算的nextTerm
i++; // 计数器递增
}
printf("\n"); // 打印完所有项后换行

return 0;
}

解析:

变量初始化: n用于存储用户输入的项数;i 作为循环计数器,从0开始;t1t2分别存储斐波那契数列的当前项和下一项,初始为F(0)=0和F(1)=1。使用long long 类型是为了避免当 n 较大时,斐波那契数超出 int范围而发生溢出。

用户输入: 提示用户输入 n

特殊情况处理: 如果 n为0,直接输出“没有项”。如果n为1,只打印F(0)即0。

while 循环条件:while (i < n),只要当前打印的项数 i小于用户要求的总项数n ,就继续循环。

循环体:

printf("%lld ", t1);:打印当前项t1

nextTerm = t1 + t2;:根据斐波那契数列的定义,计算下一项。

t1 = t2; :将 t2 的值赋给t1,为下一次迭代做准备。

t2 = nextTerm; :将新计算的 nextTerm 赋给 t2

i++;:循环计数器递增,确保循环最终会终止。

  1. 编程题:数字反转

编写一个C程序,使用 while循环将一个正整数的各位数字反转。例如,输入12345,输出54321。

示例输入:12345

示例输出:反转后的数字是: 54321

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main() {
int num, reversed_num = 0, remainder;

printf("请输入一个正整数: ");
scanf("%d", &num);

// 当原始数字不为0时,继续循环
while (num != 0) {
remainder = num % 10; // 获取当前数字的最后一位 (个位)
reversed_num = reversed_num * 10 + remainder; // 将个位添加到反转数字的末尾
num /= 10; // 移除原始数字的最后一位
}

printf("反转后的数字是: %d\n", reversed_num);
return 0;
}

解析:

变量初始化: num存储用户输入的原始数字;reversed_num初始化为0,用于构建反转后的数字;remainder用于存储每次取出的个位数字。

while 循环条件:while (num != 0),只要原始数字 num不为0,就说明还有位可以提取,循环继续。当num最终变为0时,表示所有位都已处理完毕,循环终止。

循环体逻辑:

reversed_num * 10 :将reversed_num当前存储的数字向左移动一位(相当于乘以10),为新提取的个位腾出位置。

+ remainder :将新提取的remainder加到空出的个位上。

举例追踪:

初始: num=12345 , reversed_num=0

第一次: remainder=5 , reversed_num = 0*10 + 5 = 5

第二次: num=1234 , remainder=4, reversed_num = 5*10 + 4 = 54

第三次: num=123 , remainder=3, reversed_num = 54*10 + 3 = 543

…依此类推

remainder = num % 10;:使用取模运算符% 获取 num的最后一位数字。例如,12345 % 10 结果是 5。

reversed_num = reversed_num * 10 + remainder;:这是构建反转数字的关键步骤。

num /= 10;:使用整除运算符/ 移除 num的最后一位数字。例如,12345 / 10 结果是 1234。这样,在下一次循环中,新的个位就成了旧的十位。

循环终止: 当 num最终被除为0时,循环结束,reversed_num中存储的就是反转后的数字。

这个题目很好地展示了 while循环在数字处理中的灵活应用,尤其是通过不断取模和整除来分解和重构数字的技巧。