while文

ここでは while を使った繰り返し文をおこなってみましょう。
while文を使うことで、同じ処理や似た処理を繰り返しておこなわせることができます。
繰り返しのことをループと呼びます。

動かしてみよう

早速サンプルコードを動かしてみましょう。
入力値の階乗を計算するサンプルを用意しました。
(階乗:自分以下の値を全て掛け合わせたもの。4の階乗の場合、4!=4×3×2×1=24)
入力欄に数字をいれて、実行ボタンを押してください。

実行できましたか?
では続けて解説をおこないます。

解説

while文の基本構文は下記です。

while( 条件式 ){ 処理 }

条件式が成立している間、処理を何回もおこないます。

inputに 3 を入れたと仮定して、サンプルコードの動きを追ってみましょう。

[1週目]

while( input > 0 )    /* input = 3 → 条件式成立 */
{                     /* output = 1(初期値) */
    output *= input;  /* output = 1 × 3 = 3 */
    input--;          /* input = 3 - 1 = 2 */
}

[2週目]

while( input > 0 )    /* input = 2 → 条件式成立 */
{                     /* output = 3 */
    output *= input;  /* output = 3 × 2 = 6 */
    input--;          /* input = 2 - 1 = 1 */
}

[3週目]

while( input > 0 )    /* input = 1 → 条件式成立 */
{                     /* output = 6 */
    output *= input;  /* output = 6 × 1 = 6 */
    input--;          /* input = 1 - 1 = 0 */
}

[4週目]

while( input > 0 )    /* input = 0 → 条件式が不成立のためwhile終了 */
{
    output *= input;
    input--;
}

printf("%d です。", output);/* 3週目終了時点での output は 6。これが出力される。 */


while文を用いることで、3×2×1 と順次計算をおこなっていることがわかると思います。

do〜while

while文の兄弟にdo〜while文がいます。
基本構文は下記です。

do{ 処理 }while( 条件式 );

while文との違いは、条件式と処理のどちらを先にやるかです。
while文は先に条件判定をおこないますが、do〜whileでは先に処理をおこないます。
それにより挙動に差がでます。

先のサンプルコードをdo〜whileに置き換えたものを用意しました。
入力値をいれて実行してみましょう。

実行できましたか。
では、先ほどと同様にinputに 3 を入れたと仮定して、サンプルコードの動きを追ってみましょう。

[1週目]

do                    /* 最初は判定無し。{}内の処理に進む */
{                     /* output = 1(初期値) */
    output *= input;  /* output = 1 × 3 = 3 */
    input--;          /* input = 3 - 1 = 2 */
}while( input > 0 );  /* input = 2 → 条件式成立。先頭の do に戻る。 */

[2週目]

do
{                     /* output = 3 */
    output *= input;  /* output = 3 × 2 = 6 */
    input--;          /* input = 2 - 1 = 1 */
}while( input > 0 );  /* input = 1 → 条件式成立。先頭の do に戻る。 */

[3週目]

do
{                     /* output = 6 */
    output *= input;  /* output = 6 × 1 = 6 */
    input--;          /* input = 1 - 1 = 0 */
}while( input > 0 );  /* input = 0 → 条件式が不成立のため、do〜while終了。このまま下に抜ける。 */

printf("%d です。", output);/* 3週目終了時点での output は 6。これが出力される。 */

whileでは4週目の先頭で処理が終わりましたが、do〜whileでは3週目の最後で処理が終わりました。
また処理順序に多少の差はあれども、両者とも 3! = 3×2×1 = 6 を算出できました。

が、実はここに1つ不具合が存在します。
注意点にて述べます。

注意点

while と do〜while は違う人。

while と do〜while は兄弟だと言いましたが、つまり違う人です。
同じ人だと思ったら怪我をします。

先のサンプルでは処理部分に完全に同じ処理を用いて、while でも do〜while でも得られる結果が同じことを確認しました。
ですが、実は同じでない時があります。
お手数ですがちょっとページを上に戻って、それぞれのサンプルコードに 0 を入れた時の結果の確認をしてみてください。

どうでしたか。
while では 0! = 1 と正しい結果が得られていたにも関わらず、do〜while では 0! = 0 と誤った結果が得られてしまったと思います。(数学的に 0! = 1 と定義されているので、whileの結果が正解です。)

3!は正しかったのに0!は違うとか、ホラーですね。仕事でこのミスをしたら製品によってはリコールです。その意味でもホラーですよ。。

では input = 0 を入力した時に何が起きたか見てみましょう。
while文

while( input > 0 )    /* input = 0 → 条件式が不成立のためwhile終了 */
{
    output *= input;
    input--;
}

printf("%d です。", output);/* output として 1 が出力される。(初期値のまま) */

do〜while文

do                    /* 最初は判定無し。{}内の処理に進む */
{                     /* output = 1(初期値) */
    output *= input;  /* output = 1 × 0 = 0 */
    input--;          /* input = 0 - 1 = -1 */
}while( input > 0 );  /* input = -1 → 条件式が不成立のため、do〜while終了。このまま下に抜ける。 */

printf("%d です。", output);/* output として 0 が出力される。 */

do〜whileはその性質上、最初に一回処理をやるんでしたね。
そのため入力値が 0 だった場合に、やらなくていい output = 1×0 = 0 をやってしまい、誤った結果を出しています。
プログラム設計時には、while と do〜while のどちらを使うか、一度熟考が必要です。
(do〜whileが悪いわけではないです。今回の例では while が適切だったということです。)

無限ループ

while文でやりがちなミスとして、抜けられないループ(無限ループ)を作ってしまう場合があります。
いざプログラムを書いて実行!あれ、うんともすんとも言わないな。
それが無限ループです。

事例をみてみましょう。

while( input > 0 )
{
    output *= input;
}

input−− の入れ忘れですね。while から出れません。

次に多少気づきにくい事例もみてみましょう。(サンプルとはやや式を変えています。)

unsigned int input = 3;
while( input >= 0 )
{
    output *= input;
    input--;
}

input の型が符号無しであり負値とならないため、input >= 0 となりません。
コーディングした人は input−− で対応してるつもりでも、input = 0 – 1 = 65535 となります。
(この現象をアンダーフローといいました。変数と型参照。)
input を符号有りにするなどの対応が必要です。

まとめ

まとめです。

  • while で処理が繰り返せます。
  • do〜while でも処理が繰り返せます。
  • while と do〜while は兄弟だけど他人。ちょっと動きが違います。
  • 無限ループに気をつけましょう。

以上です。
ではまた。

タイトルとURLをコピーしました