Skip to content

第 16 课:while 循环 ​

蛙蛙在课上听到老师讲"愚公移山"的小故事。愚公一家日复一日、年复一年地挖山不止。他们的事迹逐渐传遍了周边的村落。起初,人们大多持怀疑和嘲笑的态度,但随着时间的推移,看到愚公一家始终坚定不移,不少人被他们的精神打动,纷纷加入挖山的队伍中。队伍越来越壮大,大家齐心协力,挖山的进度也越来越快。

终于,愚公的坚持和执着感动了天帝。天帝被他不畏艰难、持之以恒的精神深深打动,便派夸娥氏的两个儿子下凡,将两座大山移走。

蛙蛙觉得愚公日复一日地移山这一行为可以用循环结构表示,但是并不能确定循环多少次后能够"感动天帝"。因为 i 的范围不确定,所以用 for 循环并不是特别合适,那该怎么表示呢?

16.1 while 循环的基本框架 ​

氪町博士告诉蛙蛙,对于这种不清楚循环次数,但是知道循环条件的问题,我们可以使用 while 循环去解决,可以这样表示:

cpp
while(尚未感动天帝)
{
    移山;
}

其中 while 是一种条件循环语句,它会先对括号内的条件进行判断。若条件为真(也就是满足"尚未感动天帝"这个条件),程序就会执行大括号 {} 里的代码块,再回来判断条件是否还满足。只要条件持续为真,代码块就会不断重复执行;一旦条件变为假(不满足条件),循环就会停止。

在愚公移山的故事背景下,"尚未感动天帝"这个条件就是一个判定标准,只要天帝还没被感动,愚公移山的行动就不会停止。

16.2 while 中的死循环 ​

在 while 循环语句中,如果循环条件(即小括号内的条件)永远成立,循环就会一直执行,造成死循环。比如下面这串代码,看看编译运行后会发生什么事情吧。

cpp
#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

解析

  1. 声明整型变量 h 表示当前纸张的厚度,初始化为 1(单位为毫米)。第一次对折后,纸张厚度变为 2,再对折变成 4、8、16、32……当厚度超过 n 时则停止对折,即:
cpp
while(h <= n)
{
    h *= 2;
}
  1. 我们要求的是对折的次数。因此需要先声明一个整型变量 cnt 表示对折的次数,每对折一次,cnt 加 1,在循环体内执行 cnt++,直到纸张厚度大于 n,即:
cpp
while (h <= n)
{
    cnt++;
    h *= 2;
}

参考代码

cpp
#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 的时候结束,即:

cpp
while (s <= n)
{
    s = s + i;
    i++;
}

参考代码

cpp
#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,再转换成字符类型),即:

cpp
cin >> a;
while (a != '0')
{
    cout << (char)(a + 32) << " "; // 大写字母转换为小写字母
    cin >> a;
}

注:原书解析中的代码使用 endl 输出,与参考代码、输出样例(空格隔开)不一致,此处已统一为 " "。

参考代码

cpp
#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

解析

  1. 循环体内输入整数 a,当 a 等于 0 的时候跳出循环,否则将输入的整数保存到整型变量 s 中,s 初始化为 0,用 cnt 来记录输入了几个数,即:
cpp
cin >> a;
while (a != 0)
{
    cnt++;
    s += a;
    cin >> a;
}
  1. 求平均值,即用输入的整数之和 s 除以整数的个数 cnt,即:
cpp
cout << s / cnt;

参考代码

cpp
#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;
}

基于 MIT 协议发布