第 16 课:while 循环
蛙蛙在课上听到老师讲"愚公移山"的小故事。愚公一家日复一日、年复一年地挖山不止。他们的事迹逐渐传遍了周边的村落。起初,人们大多持怀疑和嘲笑的态度,但随着时间的推移,看到愚公一家始终坚定不移,不少人被他们的精神打动,纷纷加入挖山的队伍中。队伍越来越壮大,大家齐心协力,挖山的进度也越来越快。
终于,愚公的坚持和执着感动了天帝。天帝被他不畏艰难、持之以恒的精神深深打动,便派夸娥氏的两个儿子下凡,将两座大山移走。
蛙蛙觉得愚公日复一日地移山这一行为可以用循环结构表示,但是并不能确定循环多少次后能够"感动天帝"。因为 i 的范围不确定,所以用 for 循环并不是特别合适,那该怎么表示呢?
16.1 while 循环的基本框架
氪町博士告诉蛙蛙,对于这种不清楚循环次数,但是知道循环条件的问题,我们可以使用 while 循环去解决,可以这样表示:
while(尚未感动天帝)
{
移山;
}其中 while 是一种条件循环语句,它会先对括号内的条件进行判断。若条件为真(也就是满足"尚未感动天帝"这个条件),程序就会执行大括号 {} 里的代码块,再回来判断条件是否还满足。只要条件持续为真,代码块就会不断重复执行;一旦条件变为假(不满足条件),循环就会停止。
在愚公移山的故事背景下,"尚未感动天帝"这个条件就是一个判定标准,只要天帝还没被感动,愚公移山的行动就不会停止。
16.2 while 中的死循环
在 while 循环语句中,如果循环条件(即小括号内的条件)永远成立,循环就会一直执行,造成死循环。比如下面这串代码,看看编译运行后会发生什么事情吧。
#include <iostream>
using namespace std;
int main()
{
while (1)
{
cout << "这是一个死循环" << endl;
}
return 0;
}编译运行后显示如下:
这是一个死循环
这是一个死循环
这是一个死循环
这是一个死循环
这是一个死循环
这是一个死循环
……这里的 while 循环的条件是 1,在 C++ 里,非零值代表布尔值 true,因此 while(1) 意味着循环条件永远为真,在循环体内部,程序会一直使用 cout 语句打印字符串"这是一个死循环"。
16.3 实例讲解
例 1:数学竞赛
蛙蛙正在参加一场紧张激烈的数学竞赛,各路数学高手云集。比赛进入关键的环节,一道极具挑战性的题目出现在大屏幕上,题目如下:
有一张厚度为 1 毫米的超级纸,请计算出,将这张纸对折多少次,纸的厚度才能超过 n 毫米。
竞赛场上每一秒都非常宝贵,参赛选手们都在借助各种工具争分夺秒地思考和计算。此时蛙蛙想到了使用编程的方式来计算,很快就回答了出来。他是怎么做的呢?
【输入格式】输入一行,一个整数 n,代表需要超过的 n 毫米。
【输出格式】输出一行,一个整数,表示对折的次数。
【输入样例】30
【输出样例】5
解析
- 声明整型变量 h 表示当前纸张的厚度,初始化为 1(单位为毫米)。第一次对折后,纸张厚度变为 2,再对折变成 4、8、16、32……当厚度超过 n 时则停止对折,即:
while(h <= n)
{
h *= 2;
}- 我们要求的是对折的次数。因此需要先声明一个整型变量 cnt 表示对折的次数,每对折一次,cnt 加 1,在循环体内执行
cnt++,直到纸张厚度大于 n,即:
while (h <= n)
{
cnt++;
h *= 2;
}参考代码
#include <iostream>
using namespace std;
int main()
{
int n, h = 1, cnt = 0;
cin >> n;
while (h <= n)
{
cnt++;
h *= 2;
}
cout << cnt;
return 0;
}例 2:商贩的目标
蛙蛙来到一个繁华热闹的小镇,这里有一个勤劳的小商贩,他每天都会去集市上摆摊卖东西,并且每天的收入都在逐渐增长。
第一天,小商贩的生意刚刚起步,只赚了 1 元钱;第二天,他积累了一些经验,收入增加到了 2 元;第三天,随着顾客越来越多,他赚了 3 元……此后,他每天的收入都按照这样的规律不断上升。
小商贩心里有一个梦想:他想要存够一笔钱去扩大自己的生意规模,假设他想存的总金额是 n 元。他很想知道,按照自己目前的收入增长方式,到第几天时,他累计存下的钱数会超过这个目标金额 n。
【输入格式】输入一行,一个整数 n(1 ≤ n ≤ 10000)。
【输出格式】输出一行,一个整数,表示小商贩总收入刚超过 n 时的天数。
【输入样例】50
【输出样例】10
解析
声明变量 i 表示当前项数,初始化为 1;声明变量 s 表示总和,初始化为 0。输入整数 n,当 s > n 的时候结束,即:
while (s <= n)
{
s = s + i;
i++;
}参考代码
#include <iostream>
using namespace std;
int main()
{
int n, s = 0, i = 1;
cin >> n;
while (s <= n)
{
s = s + i;
i++;
}
cout << i - 1;
return 0;
}例 3:大写字母转换为小写字母
蛙蛙接到一个需求,要求用户不断输入大写字母,当输入 0 时终止,程序把此前输入的大写字母转换为小写字母并展示。
【输入格式】输入一行,为若干个用空格隔开的大写字母,以 0 结尾。
【输出格式】输出一行,为每个大写字母对应的小写字母,用空格隔开。
【输入样例】A C D 0
【输出样例】a c d
解析
声明字符型变量 a 表示输入的大写字母,循环条件为输入的 a 不为 0,当输入 0 的时候跳出循环体,循环体内将大写字母转换成小写字母(由于大写字母的 ASCII 码比小写字母小 32,所以需要将字符变量 a 加 32,再转换成字符类型),即:
cin >> a;
while (a != '0')
{
cout << (char)(a + 32) << " "; // 大写字母转换为小写字母
cin >> a;
}注:原书解析中的代码使用
endl输出,与参考代码、输出样例(空格隔开)不一致,此处已统一为" "。
参考代码
#include <iostream>
using namespace std;
int main()
{
char a;
cin >> a;
while (a != '0')
{
cout << (char)(a + 32) << " ";
cin >> a;
}
return 0;
}例 4:取整数平均值
蛙蛙希望输入若干个正整数,当输入 0 时停止输入,要求计算并输出这些正整数的平均值(结果取整)。
【输入格式】输入一行,为若干个用空格隔开的整数,以 0 结尾。
【输出格式】输出一行,一个整数,表示输入整数的平均值。
【输入样例】1 2 3 4 5 0
【输出样例】3
解析
- 循环体内输入整数 a,当 a 等于 0 的时候跳出循环,否则将输入的整数保存到整型变量 s 中,s 初始化为 0,用 cnt 来记录输入了几个数,即:
cin >> a;
while (a != 0)
{
cnt++;
s += a;
cin >> a;
}- 求平均值,即用输入的整数之和 s 除以整数的个数 cnt,即:
cout << s / cnt;参考代码
#include <iostream>
using namespace std;
int main()
{
int a, s = 0, cnt = 0;
cin >> a;
while (a != 0)
{
cnt++;
s += a;
cin >> a;
}
cout << s / cnt;
return 0;
}