C语言小课堂:do-while语句

今天,我们要深入了解一个有点“特别”的循环——do-while 语句。它不像你可能熟悉的 whilefor 循环那样“先看后做”,而是有点“不回头”的执着,先做一次再说!

  1. do-while:“先做再说,至少一次”

do-while 循环是 C 语言提供的一种后测试循环结构。它的基本语法如下:

do {
// 循环体(要重复执行的代码)
} while (条件表达式); // 注意这里有一个分号!

do 关键字:表示循环体的开始。

循环体:包含了一组需要重复执行的语句。

while (条件表达式):在循环体执行完毕后,才会对条件表达式进行判断。

分号 ;:这是 do-while 循环特有的,while 后必须跟着一个分号,表示循环语句的结束。

while 循环(先判断条件,再执行循环体)不同,do-while 循环的特点是无论条件表达式是否为真,循环体至少会执行一次。 只有在第一次执行完毕后,才会检查条件表达式。如果条件为真,则继续执行下一次循环;如果条件为假,则退出循环。

  1. 何时用do-while?

do-while 循环在编程中扮演着独特的角色,尤其适用于以下场景:

至少执行一次的场景:这是 do-while 最核心的应用场景。例如,要求用户输入一个有效值,如果输入无效则一直提示重新输入,直到输入有效为止。无论用户第一次输入什么,我们都希望至少给他们一次输入的机会。

用户交互菜单:在构建基于文本的菜单程序时,do-while 循环非常方便。我们可以先显示菜单并获取用户选择,然后根据选择判断是否继续显示菜单或执行其他操作。

需要初始化后才能判断的场景:有些情况下,循环的条件判断依赖于循环体内部产生的值。例如,计算一个序列的和,你需要先执行一次循环来产生第一个值,然后才能根据这个值来判断是否继续。

while 循环的区别与联系:

特性 while 循环 do-while 循环
测试时机 先测试条件,后执行循环体 先执行循环体,后测试条件
执行次数 循环体可能执行 0 次或多次 循环体至少执行 1 次或多次
应用场景 适用于循环体可能不需要执行的场景 适用于循环体至少需要执行一次的场景
语法 while (条件) { ... } do { ... } while (条件);

简单来说,如果你确定你的代码逻辑至少要执行一次,那么 do-while 就是你的不二选择。如果你不确定是否需要执行,或者可能一次都不需要执行,那么 whilefor 循环会更合适。

  1. 怎么用do-while?

让我们通过几个实际例子来感受 do-while 的魅力。

示例一:用户输入校验

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

int main() {
int score;
do {
printf("请输入你的考试分数(0-100):");
scanf("%d", &score);
if (score < 0 || score > 100) {
printf("分数无效,请重新输入!\n");
}
} while (score < 0 || score > 100); // 只要分数无效,就继续循环

printf("你输入的分数是:%d\n", score);

return 0;
}

代码解析:在这个例子中,无论用户第一次输入什么,程序都会先执行 scanf 获取分数。然后,while 语句会检查分数是否在有效范围内。如果不在,就会继续循环,直到用户输入一个有效分数为止。

示例二:简单的菜单选择

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
#include <stdio.h>

int main() {
int choice;
do {
printf("\n--- 菜单 ---\n");
printf("1. 开始游戏\n");
printf("2. 查看设置\n");
printf("3. 退出\n");
printf("请选择你的操作:");
scanf("%d", &choice);

switch (choice) {
case 1:
printf("游戏开始!\n");
break;
case 2:
printf("进入设置界面。\n");
break;
case 3:
printf("感谢使用,再见!\n");
break;
default:
printf("无效选择,请重新输入!\n");
break;
}
} while (choice != 3); // 只要用户没有选择退出,就继续显示菜单

return 0;
}

代码解析:这个程序会先显示菜单并获取用户选择,然后根据选择执行相应的操作。如果用户输入的不是 3 (退出),do-while 循环就会再次执行,重新显示菜单,直到用户选择退出为止。这确保了菜单至少会显示一次。

示例三:计算 1 到 n 的和(使用 do-while)

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

int main() {
int n, sum = 0, i = 1;
printf("请输入一个正整数 n:");
scanf("%d", &n);

// 假设 n >= 1
if (n >= 1) { // 确保 n 是正整数,否则 do-while 可能会无限循环或不符合预期
do {
sum += i;
i++;
} while (i <= n);
} else {
printf("输入无效,n 必须是正整数。\n");
}

printf("1 到 %d 的和是:%d\n", n, sum);
return 0;
}

代码解析:这个例子展示了如何使用 do-while 来累加。即使 n 为 1,循环体也会至少执行一次(sum += 1; i++),然后 i 变为 2, i <= n (2 <= 1) 为假,循环退出。确保了即使只计算 1 到 1 的和,也能正确执行。

二、配套习题设计

习题一(选择题)

以下关于 do-while 循环的描述,哪一项是正确的?

A. do-while 循环的循环体可能一次都不执行。

B. do-while 循环的条件表达式在循环体执行之前判断。

C. do-while 循环的 while 后面必须带分号。

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

习题二(判断题)

do-while 循环可以完全被 while 循环替代,且不改变程序的行为。

A.正确

B.错误

习题三(填空题)

请填写代码,使得该 do-while 循环能够打印数字 5 到 1,然后结束。

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

习题四(编程题)

编写一个 C 语言程序,使用 do-while 循环实现一个简单的猜数字游戏。 程序随机生成一个 1 到 100 之间的整数,然后提示用户输入猜测的数字。 如果用户猜错了,程序会提示“太大了”或“太小了”,直到用户猜对为止。 每当用户猜对后,程序应显示“恭喜你,猜对了!”并显示用户猜测的次数。

提示:

使用 rand() 函数生成随机数,需要包含 <stdlib.h><time.h>

使用 srand(time(NULL)) 初始化随机数种子。

习题五(编程题)

编写一个 C 语言程序,使用 do-while 循环计算并打印斐波那契数列(Fibonacci sequence)的前 N 项。斐波那契数列的定义是:F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2) (n >= 2)。程序应确保用户输入的 N 是一个正整数(大于等于 1)。

要求:

提示用户输入要打印的斐波那契数列项数 N。

使用 do-while 循环确保用户输入的 N 是一个大于等于 1 的整数。

使用 do-while 循环计算并打印斐波那契数列的前 N 项。

如果 N 为 1,只打印 0;如果 N 为 2,打印 0 1。

三、习题讲解

习题一(选择题)

以下关于 do-while 循环的描述,哪一项是正确的?

A. do-while 循环的循环体可能一次都不执行。

B. do-while 循环的条件表达式在循环体执行之前判断。

C. do-while 循环的 while 后面必须带分号。

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

答案:C

解析:

A 选项错误: do-while 循环的特点是先执行循环体,后判断条件,所以循环体至少会执行一次。

B 选项错误: do-while 循环是后测试循环,条件表达式在循环体执行之后才判断。

C 选项正确:这是 do-while 语法的强制要求,while (条件表达式); 后面必须有一个分号。

D 选项错误: do-while 循环通常用于循环次数不确定,但至少需要执行一次的场景,例如用户输入校验。已知循环次数的场景更适合使用 for 循环。

习题二(判断题)

do-while 循环可以完全被 while 循环替代,且不改变程序的行为。 ( )

答案:F (错误)

解析: do-while 循环和 while 循环的主要区别在于循环体执行的次数。do-while 循环保证循环体至少执行一次,而 while 循环在条件不满足时可能一次都不执行。

虽然我们可以通过在 while 循环前复制一份循环体的代码,来模拟 do-while 至少执行一次的行为,例如:

// do-while
do {
// some code
} while (condition);

// 等价的 while 模拟
// some code; // 第一次执行
// while (condition) {
// // some code; // 后续执行
// }

但这种替代方式并不“完全”且“不改变程序的行为”,因为它引入了代码重复,并且在逻辑上不如 do-while 语句直接清晰地表达“至少执行一次”的意图。在某些情况下,如果条件一开始就为假,while 循环将不执行,而 do-while 依然会执行一次,这时它们的行为就不同了。因此,不能说它们可以完全互相替代而不改变程序的行为。

习题三(填空题)

请填写代码,使得该 do-while 循环能够打印数字 5 到 1,然后结束。

#include <stdio.h>
int main() {
int num = 5; // 初始值为 5
do {
printf("%d ", num);
num--;
} while (num >= 1 ); // 当 num 大于等于 1 时继续循环
printf("\n");
return 0;
}

答案: num = 5;num >= 1;

解析:

我们希望从 5 开始打印,所以 num 的初始值应设为 5。

循环体每次打印 num 并将其减 1。

循环需要持续到 num 变为 1 也要打印,然后当 num 减到 0 时停止。因此,循环条件应该是 num >= 1。当 num 变为 0 时,条件 0 >= 1 为假,循环终止。

习题四(编程题)

题目: 编写一个 C 语言程序,使用 do-while 循环实现一个简单的猜数字游戏。程序随机生成一个 1 到 100 之间的整数,然后提示用户输入猜测的数字。如果用户猜错了,程序会提示“太大了”或“太小了”,直到用户猜对为止。每当用户猜对后,程序应显示“恭喜你,猜对了!”并显示用户猜测的次数。

代码:

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
34
35
#include <stdio.h>
#include <stdlib.h> // 用于 rand() 和 srand()
#include <time.h> // 用于 time()

int main() {
int randomNumber;
int guess;
int guessCount = 0;

// 初始化随机数种子
srand(time(NULL));

// 生成 1 到 100 之间的随机数
randomNumber = (rand() % 100) + 1;

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

do {
printf("请输入你的猜测:");
scanf("%d", &guess);
guessCount++; // 每次猜测都增加计数

if (guess < randomNumber) {
printf("太小了,再大一点!\n");
} else if (guess > randomNumber) {
printf("太大了,再小一点!\n");
} else {
printf("恭喜你,猜对了!\n");
printf("你一共猜了 %d 次。\n", guessCount);
}
} while (guess != randomNumber); // 只要没猜对,就继续循环

return 0;
}

解析:

随机数生成:srand(time(NULL)) 用于初始化随机数生成器,确保每次运行程序时都能生成不同的随机数。randomNumber = (rand() % 100) + 1; 生成 1 到 100 之间的整数。

do-while 的应用: 游戏至少要让用户猜一次,所以 do-while 循环非常适合。do 块内包含获取用户输入、增加猜测次数和判断猜测结果的逻辑。

循环条件:while (guess != randomNumber); 表示只要用户猜的数字不等于随机数,循环就会继续执行。一旦猜对,条件 guess != randomNumber 为假,循环终止。

计数器: guessCount 变量在每次用户猜测后递增,用于记录猜测次数。

习题五(编程题)

题目: 编写一个 C 语言程序,使用 do-while 循环计算并打印斐波那契数列(Fibonacci sequence)的前 N 项。斐波那契数列的定义是:F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2) (n >= 2)。程序应确保用户输入的 N 是一个正整数(大于等于 1)。

代码:

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
34
35
36
37
38
39
40
#include <stdio.h>

int main() {
int n;
long long a = 0, b = 1; // 使用 long long 防止溢出,因为斐波那契数列增长很快
long long nextTerm;
int count = 0;

// 确保用户输入 N 是正整数
do {
printf("请输入要打印的斐波那契数列项数 N (N >= 1):");
scanf("%d", &n);
if (n < 1) {
printf("N 必须是正整数,请重新输入!\n");
}
} while (n < 1);

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

// 使用 do-while 循环打印斐波那契数列
// 特殊处理 N=1 和 N=2 的情况
if (n == 1) {
printf("%lld\n", a); // 打印 F(0)
} else if (n >= 2) {
printf("%lld %lld ", a, b); // 打印 F(0) 和 F(1)
count = 2; // 已经打印了两项

// 从第三项开始计算和打印
do {
nextTerm = a + b;
printf("%lld ", nextTerm);
a = b;
b = nextTerm;
count++;
} while (count < n); // 只要还没达到 N 项,就继续
printf("\n");
}

return 0;
}

解析:

用户输入校验 ( do-while 第一次应用):

外层的 do-while 循环 do { ... } while (n < 1); 用于确保用户输入的 n 是一个大于等于 1 的正整数。无论用户第一次输入什么,程序都会执行一次输入提示和获取。如果输入无效,它会继续提示,直到输入有效为止。

斐波那契数列计算与打印 (do-while 第二次应用):

内部的 do-while 循环 do { ... } while (count < n); 开始计算并打印从第三项开始的斐波那契数。

每次循环:

循环条件 count < n 确保循环继续执行直到打印了 n 项。即使 n=2 并且已经打印了 0 1,这个 do-while 循环也不会执行(因为 count 已经等于 n),这符合预期。

nextTerm = a + b; 计算下一项。

printf("%lld ", nextTerm); 打印当前项。

a = b;b = nextTerm; 更新 ab 的值,为下一次循环做准备。

初始化: ab 分别初始化为斐波那契数列的前两项 F(0) = 0 和 F(1) = 1。nextTerm 用于存储下一项的值,count 用于记录当前已打印的项数。

特殊情况处理: 由于斐波那契数列的定义是 F(0) 和 F(1) 是固定的,从 F(2) 开始才由前两项相加得到,所以需要对 n=1n=2 进行特殊处理,直接打印 F(0) 和 F(0) F(1)。

循环打印: 当 n >= 2 时,在打印了 F(0) 和 F(1) 后,count 初始化为 2。

数据类型: 使用 long long 来存储斐波那契数,因为斐波那契数列增长非常快,int 类型很快就会溢出。

通过这两个编程题,你是不是对 do-while 循环的“至少执行一次”特性有了更深刻的理解呢?记住,选择合适的循环结构是写出高效、清晰代码的关键哦!