C言語の基本|while文とループ

続けるか、終わるかを毎回チェック。while文で、条件に合わせて動くループを身につけよう。

プログラムでは、同じ処理を何度も実行したい場面がよくあります。

たとえば、倉庫の荷物を順番に搬送したり、入力された数値を合計したり、正しい値が入力されるまで確認を続けたりする処理です。

同じ文を必要な回数だけ書き並べる方法では、回数が増えるほどプログラムが長くなってしまいます。そこで使うのが、処理を繰り返すためのループです。

C言語には、主に次の繰り返し文があります。

制御文得意な繰り返し処理の特徴
while条件を満たしている間の繰り返し実行前に条件を確認する
for回数や範囲が決まっている繰り返し初期化・条件・更新をまとめて書ける
do~while最低でも1回は実行する繰り返し実行後に条件を確認する
breakループを途中で終了するループの外へ抜ける
continue今回の処理を途中で切り上げる次の繰り返しへ進む

この中でもwhile文は、条件が真である間だけ処理を繰り返すという、ループの基本的な仕組みを理解しやすい制御文です。

図1:while文が条件を確認して繰り返す流れ

この図から分かること

while文では、ループ本体を実行する前に継続条件を確認します。

条件が真ならループ本体を実行し、変数を更新してから再び条件判定へ戻ります。条件が偽になるとループを終了し、while文の後にある処理へ進みます。

while文は前判定の繰り返し

while文の大きな特徴は、繰り返す処理よりも先に条件式を評価することです。このような仕組みを前判定と呼びます。

処理の順番は次のとおりです。

  1. 継続条件式を評価する
  2. 条件式が真ならループ本体を実行する
  3. ループ本体を終えたら条件判定へ戻る
  4. 条件式が偽になるまで繰り返す
  5. 条件式が偽になったらwhile文を終了する

最初の条件判定が偽だった場合は、ループ本体が一度も実行されません。

この点が、処理を実行してから条件を確認するdo~while文との大きな違いです。

while文の基本構文

while文は、次の形で記述します。

while (継続条件式) {
    繰り返す文;
}

構文の各部分には、次の役割があります。

要素役割注意点
while繰り返しを開始する丸括弧内に継続条件式を書く
継続条件式ループを続けるか判断する真の間は繰り返し、偽になると終了する
波括弧ループ本体の範囲を示す複数の文をひとまとまりにする
ループ本体条件が真の間に繰り返す処理条件を変化させる更新処理も確認する

C言語では、継続条件式の値が0なら偽、0以外なら真として扱います。

通常は、次のような関係演算子を使って条件式を作ります。

while (count < 5)

この条件では、countが5未満である間、ループ本体を繰り返します。

1文だけでも波括弧を付ける

while文のループ本体が1文だけなら、波括弧を省略できます。

while (count < 5)
    count++;

ただし、学習中は1文だけでも波括弧を付ける書き方がおすすめです。

while (count < 5) {
    count++;
}

波括弧を付けると、次の点が分かりやすくなります。

  • どの文が繰り返されるのか
  • 更新処理がループ内にあるか
  • 後から文を追加する場所
  • while文の終了位置

インデントも揃えると、ループ本体の範囲を目で追いやすくなります。

while文に必要な3つの要素

while文を作るときは、初期化・条件・更新という3つの要素を確認します。

要素役割
初期化ループ開始前の状態を決めるcount = 0
条件ループを続けるか判断するcount < 5
更新次の繰り返しに向けて状態を変えるcount++

基本的な配置は次のようになります。

初期化;

while (継続条件式) {
    繰り返す処理;
    更新;
}

初期化では、条件判定に使う変数の開始値を決めます。

継続条件式では、どの状態まで処理を続けるかを指定します。

更新では、条件式に使っている変数を変化させます。この更新によって、ループは少しずつ終了条件へ近づきます。

図2:while文を支える初期化・条件・更新

この図から分かること

初期化はループの開始前に一度だけ行います。条件はループへ入る前と、ループ本体を実行した後に毎回確認されます。

ループ本体の更新処理によって状態が変化し、やがて継続条件が偽になります。更新がなければ同じ状態のまま条件を繰り返し確認するため、ループが終わらない可能性があります。

荷物を5個ずつ搬送する

次のプログラムでは、倉庫にある荷物を5個ずつ搬送します。

荷物が5個以上残っている間は、次の処理を繰り返します。

  • 荷物を5個減らす
  • 搬送回数を1増やす
  • 搬送回数と残りの荷物数を表示する

残りが5個未満になったら、while文を終了します。

荷物を5個ずつ搬送して回数を数えるプログラム

ファイル名:9_1_1.c

#include <stdio.h>

int main(void)
{
    int packages;
    int count = 0;

    printf("倉庫にある荷物の個数を入力してください > ");
    scanf("%d", &packages);

    /* 荷物が5個以上ある間、5個ずつ搬送する */
    while (packages >= 5) {
        packages -= 5;
        count++;

        printf("%d回目の搬送が完了しました。残りは%d個です。\n",
               count, packages);
    }

    printf("5個まとめて搬送できる処理は終了しました。\n");
    printf("搬送回数は%d回、残りは%d個です。\n", count, packages);

    return 0;
}
実行結果の例

荷物の個数に17を入力した場合は、ループ本体が3回実行されます。

倉庫にある荷物の個数を入力してください > 17
1回目の搬送が完了しました。残りは12個です。
2回目の搬送が完了しました。残りは7個です。
3回目の搬送が完了しました。残りは2個です。
5個まとめて搬送できる処理は終了しました。
搬送回数は3回、残りは2個です。

最初から荷物が5個未満の場合は、ループ本体が一度も実行されません。

倉庫にある荷物の個数を入力してください > 3
5個まとめて搬送できる処理は終了しました。
搬送回数は0回、残りは3個です。
プログラムの詳しい解説

packagesには、入力された荷物の個数を格納します。

int packages;

countは搬送回数を数える変数です。搬送を始める前なので、0で初期化しています。

int count = 0;

while文の継続条件は、荷物が5個以上残っていることです。

while (packages >= 5)

packagesが17の場合、最初の条件判定は真です。そのため、ループ本体へ入ります。

ループ本体では、最初に荷物を5個減らします。

packages -= 5;

続いて、搬送回数を1増やします。

count++;

1回目の処理後は、packagesが12、countが1になります。ループ本体を終えると、もう一度packages >= 5を評価します。

12は5以上なので、2回目の処理へ進みます。

条件を確認する時点packagespackages >= 5動作
1回目の前175個搬送する
2回目の前125個搬送する
3回目の前75個搬送する
4回目の前2ループを終了する

packagesが2になると継続条件が偽になります。そのため4回目のループ本体には入らず、while文の後にあるprintfへ進みます。

while文の実行を順番に追う

while文の動きを理解するときは、変数の値を追いかけると分かりやすくなります。

今回のプログラムは、次の順番で動きます。

  1. countを0にする
  2. packagesを入力する
  3. packages >= 5を評価する
  4. 真ならpackagesを5減らす
  5. countを1増やす
  6. 現在の状態を表示する
  7. 条件判定へ戻る
  8. packages >= 5が偽になったら終了する

特に重要なのは、ループ本体を実行した後に、while文の先頭へ戻って条件式を再評価することです。

最初から条件が偽なら一度も実行されない

while文は前判定なので、継続条件が最初から偽ならループ本体へ入りません。

packagesが3の場合、最初の条件は次のようになります。

3 >= 5

この比較結果は偽です。そのため、荷物を減らす処理やcountを増やす処理は一度も実行されません。

countの値は初期値の0、packagesの値は入力された3のままです。

while文の外側に終了メッセージや最終結果の表示を書いておけば、ループ本体が一度も実行されなかった場合でも結果を確認できます。

カウンタ変数とループで使う変数

ループで使用する変数には、役割に応じた呼び方があります。

呼び方主な役割変数名の例
カウンタ変数実行回数を数えるcount、times
ループ変数ループの進行を管理するi、j、k
インデックス変数配列の要素番号を表すi、index
状態を表す変数継続条件の状態を持つpackages、money

今回のcountは、搬送回数を数えるカウンタ変数です。packagesは、残っている荷物の個数を表すと同時に、ループを続けるかどうかの判断にも使われています。

短いループではiがよく使われますが、変数の役割が明確な場合はcountやpackagesのような名前を付けると、処理内容を理解しやすくなります。

更新を忘れると無限ループになる

while文で起こりやすいミスが、条件式に使っている変数の更新忘れです。

int count = 0;

while (count < 5) {
    printf("%d\n", count);
}

この例では、countの値が0から変化しません。そのためcount < 5は何度評価しても真になり、ループが終わりません。

正しく終了させるには、countを変化させます。

int count = 0;

while (count < 5) {
    printf("%d\n", count);
    count++;
}

countは繰り返すたびに1ずつ増えます。やがて5になり、count < 5が偽になるためループを終了します。

図3:更新の有無で変わる正常終了と無限ループ

この図から分かること

更新があるループでは、countが少しずつ終了条件へ近づきます。countが5になると条件が偽になり、ループを終了できます。

更新がない場合はcountが0のままなので、条件がいつまでも真です。while文を書くときは、条件式に使っている変数がループ内で適切に変化しているかを確認する必要があります。

無限ループを防ぐための確認ポイント

while文を書いた後は、次の点を順番に確認すると安心です。

  • 条件式に使う変数を初期化しているか
  • 初期値に対して条件式がどのような結果になるか
  • ループ本体の中で変数が更新されているか
  • 更新によって終了条件へ近づいているか
  • いつか条件式が偽になるか
  • ループ本体が一度も実行されない場合も問題ないか

たとえば、count < 5という条件に対してcount--と更新すると、countは5から遠ざかってしまいます。更新処理が存在するだけではなく、条件を偽にする方向へ変化していることが大切です。

while文を読みやすく書くコツ

while文では、処理の範囲と変数の変化が見える書き方を心がけます。

  • ループ本体はインデントを1段下げる
  • 処理が1文でも波括弧を付ける
  • 初期化をwhile文の近くに書く
  • 更新処理を分かりやすい位置に置く
  • 変数の役割が伝わる名前を付ける
  • 終了条件を具体的に考える

while文は、繰り返す回数が最初から決まっていない処理に向いています。条件の変化に応じて何回実行されるかが決まる場面では、初期化・条件・更新の関係をはっきりさせることで、安全で読みやすいループを作れます。