while文 解答ページ | Programming Place Plus 新C++編

トップページ新C++編while文

このページの概要

このページは、練習問題の解答例や解説のページです。



解答・解説

問題1 (確認★)

次の2つのコードの意味を説明してください。

if (n > 0) {
    std::cout << "OK.\n";
}
while (n > 0) {
    std::cout << "OK.\n";
}


1つ目のコードは if文なので、n > 0 という “条件式が true になったときに1回だけ”、std::cout << "OK.\n"; を実行します。

2つ目のコードは while文なので、n > 0 という “条件式が true になっているあいだ”、std::cout << "OK.\n"; を実行します。変数 n の値を条件式に使っていますが、while文の内側で変数 n の値を変更していません。そのため、初回の判定で n > 0 が true になり、ループの内側に入っていったのならば、それっきりループから抜け出すことはなく、無限ループになっています(本編解説)。

問題2 (基本★)

次の while文はどういう意味ですか?

while (0) {
    // なんらかの処理
}


while文の条件式が 0 となっています。0 という整数は、bool型に直すと false ですから(「論理値」のページを参照)、この while文の条件式は「必ず false」です。

したがって、この while文の内側に入ることはなく、「なんらかの処理」が実行されることもありません。

問題3 (基本★)

次の for文を、同じ結果になるように while文で書き換えてください。

for (int i = 0; i < 5; ++i) {
    std::cout << i << "\n";
}


この for文は典型的な回数指定のループになっていて、5回だけループします(「for文」のページを参照)。周回のたびに、変数 i の値を出力するので、実行結果はこうなります。

0
1
2
3
4

while文で同じことをするのなら、次のように書きます。

#include <iostream>

int main()
{
    int i {0};
    while (i < 5) {
        std::cout << i << "\n";
        ++i;
    }
}

実行結果:

0
1
2
3
4

for文の int i = 0; の部分は、for文の実行の最初にだけ実行されるものですから、while文であれば、while文に入る直前で実行します。

条件式が確認されるタイミングは for文でも while文でも同じですし、意味も同じなので、ここは特に変える必要はありません。

for文の ++i は、周回が終わるたびに実行されるものなので、while文なら、内側の処理の末尾で行えばいいです。

これで同じ意味になりますが、変数 i の宣言がループの外に飛び出してしまう点に不満もありますし、for文で書いた方が自然です。

問題4 (基本★★)

次の for文を、同じ結果になるように do文で書き換えてください。

for (int i = 0; i < 5; ++i) {
    std::cout << i << "\n";
}


今度は do文に書き換えます。

#include <iostream>

int main()
{
    int i {0};
    do {
        std::cout << i << "\n";
        ++i;
    } while (i < 5);
}

実行結果:

0
1
2
3
4

for文の int i = 0; の部分は、for文の実行の最初にだけ実行されるものですから、do文であれば、do文に入る直前で実行します。do文に入ってから行うと、周回のたびに変数を宣言・初期化しなおすことになってしまいます。

条件式が確認されるタイミングが for文と do文とでは異なります。最大の違いは、ループの初回にチェックされるかどうかで、for文ならチェックされ、do文ならチェックされません。今回の場合、条件式は i < 5 であり、変数 i の初回の値は 0 であることが分かっているので、初回のチェックの有無は別に問題になりません。そのため、特に条件式を変更する必要はありません。

for文の ++i は、周回が終わるたびに実行されるものなので、do文なら、内側の処理の末尾で行えばいいです。

これで同じ意味になりますが、もちろん、for文で書いた方が自然です。


この問題では変更する必要がなかったですが、条件式が同じでいいのかどうかはよく考えなければなりません。条件式を変更しなければならないのであれば、そもそも、do文への置き換え自体が不適切な可能性も高いです。特に、do文の内側に入った直後に if文で条件確認するようなコードになるようなら、明らかに do文の使いどころが間違っています(do文は必ず1回以上はループさせるものなので)。

問題5 (基本★★)

次の do文を、同じ結果になるように、無限ループを使ったかたちに書き換えてください。

#include <iostream>

int main()
{
    int value {};
    do {
        std::cout << "Please enter the integer.\n";
        std::cin >> value;

        if (value > 0) {
            std::cout << value << " is positive number.\n";
        }
        else if (value < 0) {
            std::cout << value << " is negative number.\n";
        }
    } while (value != 0);
}


整数の入力を受け取り、0 より大きいか、0 より小さいかによってメッセージを出力し、ループを続行します。0 だったときには何も出力せずに終了します。

Please enter the integer.
3  <-- 入力した整数
3 is positive number.
Please enter the integer.
-3  <-- 入力した整数
-3 is negative number.
Please enter the integer.
0  <-- 入力した整数

do文で実現すると、変数 value がループの外側に出てしまうことがやや気になるところです。while文や for文で書くと、変数 value をループの内側に入れられます。

#include <iostream>

int main()
{
    while (true) {
        std::cout << "Please enter the integer.\n";
        int value {};
        std::cin >> value;

        if (value > 0) {
            std::cout << value << " is positive number.\n";
        }
        else if (value < 0) {
            std::cout << value << " is negative number.\n";
        }
        else {
            break;
        }
    }
}

while文に変更し、条件式を true にしました。これで必ずループに入りますから、do文の「最低でも1回はループする」という動作をマネできます。あとは、適切なタイミングで break文を使って脱出すればいいです。

入力された値が 0 のときにはループを抜け、そうでなければ続行しなければなりませんから、value == 0 のときに break文を実行するようにします。value == 0 というのは、value > 0 でも value < 0 でもないときなので、ここでは else を最後に付け足して実現しています。

問題6 (応用★★★)

末尾に .、途中にいくつかの空白(’ ’)を含んだ文字列があるとして、空白を詰めたものを出力するプログラムを、continue文を使って作成してください。

たとえは、“Hello, New World.” という文字列に対しては、“Hello,NewWorld.” を出力します。


たとえば次のようなプログラムになります。

#include <iostream>
#include <string>

int main()
{
    std::string s = "Hello, New World.";

    for (int i = 0; true; ++i) {

        // 空白文字を飛ばす
        if (s[i] == ' ') {
            continue;
        }

        std::cout << s[i];

        // ピリオドを見つけたら終了
        if (s[i] == '.') {
            break;
        }
    }
    std::cout << "\n";
}

実行結果:

Hello,NewWorld.

文字列を構成する文字の内容に応じた処理を書くには、文字列内を1文字ずつ順番に調べていくのが基本です。文字列内の文字は s[0] のようなかたちでアクセスできるのでした(「文字列の入力」のページを参照)。

ループの終了条件は、末尾の文字まで処理を終えたときです。今回は末尾に . があるという前提になっているので、これを利用すればいいですが、. 自体は出力したいので、ループの「条件式」のところで判定せずに、出力処理を終えてから判定するようにし、break文で抜け出すかたちにします。

空白を詰めるためには、調べた文字が ' ' でなければそのまま出力、' ' だったら出力しないようにすればいいです。出力させないようにするために、continue文を使って、出力処理と、ループの終了確認のコードをスキップさせています。


なお、continue文を使わなくていいのなら、次のようにも書けます。

#include <iostream>
#include <string>

int main()
{
    std::string s = "Hello, New World.";

    for (int i = 0; true; ++i) {

        // 空白文字を飛ばす
        if (s[i] != ' ') {

            std::cout << s[i];

            // ピリオドを見つけたら終了
            if (s[i] == '.') {
                break;
            }
        }
    }
    std::cout << "\n";
}


参考リンク



更新履歴




はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る