C言語の基本|do~while文の使い方

最初の1回を確実に実行し、その後で続けるかを判断する。do~while文で、入力と確認のループを自然に組み立てよう。

while文やfor文は、ループ本体へ入る前に継続条件を確認します。そのため、条件が最初から偽なら、ループ本体は一度も実行されません。

一方、do~while文は、最初にループ本体を実行してから継続条件を確認します。この仕組みを後判定と呼びます。

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

  1. ループ本体を実行する
  2. 継続条件を確認する
  3. 条件が真ならループ本体へ戻る
  4. 条件が偽ならループを終了する

条件判定よりも先にループ本体を通るため、条件の結果にかかわらず最低1回は必ず実行されます。

do~while文は、次のような処理に向いています。

  • 最低1回は入力してもらう
  • メニューを表示してから続行を確認する
  • 計算結果を表示してから、もう一度計算するか尋ねる
  • 正しい答えが入力されるまで質問する
  • 認証情報が一致するまで入力を繰り返す

図1:前判定と後判定の違い

この図から分かること

while文は条件を先に確認するため、最初から条件が偽なら処理を実行しません。

do~while文は処理を先に実行します。その後で条件を確認するため、継続条件が最初から偽になる場合でも、ループ本体は1回実行されます。

do~while文の基本構文

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

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

各部分の役割は次のとおりです。

要素役割注意点
doループ本体の開始を示すdoの直後に波括弧を書く
doのブロック繰り返し実行する処理最低1回は必ず実行される
while継続条件を指定するループ本体の後に書く
継続条件式次の繰り返しへ進むか判断する真なら継続、偽なら終了
末尾のセミコロンdo~while文の終わりを示す付け忘れるとコンパイルエラーになる

特に注意したいのは、whileの丸括弧を閉じた後にセミコロンが必要なことです。

} while (継続条件式);

while文では、条件式の後にループ本体が続くため、次のように書きます。

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

do~while文では、ループ本体が先にあり、最後のwhileで構文が終わるため、末尾にセミコロンを書きます。

do~while文の処理順序

do~while文は次の順番で動きます。

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

1回目は、条件式を確認せずに処理へ入ります。

処理が終わると、条件式を評価します。

  • 条件式が真ならdoの直後へ戻る
  • 条件式が偽ならdo~while文を終了する

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

条件式の値判定do~while文の動作
0ループを終了する
0以外次の繰り返しへ進む

while文との違い

比較項目while文do~while文
条件を確認する位置ループ本体の前ループ本体の後
判定方式前判定後判定
最小実行回数0回1回
得意な処理条件を満たす場合だけ実行最初の処理が必ず必要
使用例データがある間だけ処理入力してから正誤を確認

while文は、条件を満たさない場合に処理を一切行いたくないときに向いています。

do~while文は、入力、計算、メニュー表示などを最初に行い、その結果を使って続けるか決めたい場合に向いています。

正しい解除コードが入力されるまで繰り返す

次のプログラムでは、EV充電器の保守画面を開くための解除コードを入力します。

正しい解除コードは5317とし、一致するまで入力を繰り返します。

正しい解除コードが入力されるまで認証を続けるプログラム

ファイル名:9_7_1.c

#include <stdio.h>

int main(void)
{
    int input_code;
    const int correct_code = 5317;

    do {
        printf("保守用の解除コードを入力してください > ");
        scanf("%d", &input_code);

        if (input_code != correct_code) {
            printf("コードが違います。もう一度入力してください。\n");
        }
    } while (input_code != correct_code);

    printf("認証に成功しました。保守画面を開きます。\n");

    return 0;
}
実行結果の例
保守用の解除コードを入力してください > 1111
コードが違います。もう一度入力してください。
保守用の解除コードを入力してください > 5317
認証に成功しました。保守画面を開きます。
プログラムの詳しい解説

正しい解除コードは、変更しない値としてcorrect_codeへ格納しています。

const int correct_code = 5317;

doブロックでは、解除コードの入力を受け付けます。

scanf("%d", &input_code);

入力された値がcorrect_codeと一致しなければ、再入力を促すメッセージを表示します。

if (input_code != correct_code) {
    printf("コードが違います。もう一度入力してください。\n");
}

doブロックの最後まで進むと、継続条件を評価します。

while (input_code != correct_code);

input_codeが5317以外なら条件は真なので、doの先頭へ戻ります。

5317が入力されるとinput_code != correct_codeが偽になります。do~while文を終了し、認証成功のメッセージを表示します。

入力ループにdo~while文が向いている理由

解除コードを確認するためには、最初に何らかの値を入力してもらう必要があります。

do~while文なら、入力処理をループ本体にまとめられます。

do {
    入力する;
    入力結果を確認する;
} while (入力が正しくない);

while文で同じ流れを作る場合、最初の条件判定に使う値が必要です。そのため、入力処理をループの外側と内側に分けて書くことがあります。

最初の入力;

while (入力が正しくない) {
    再入力;
}

do~while文では、最初の入力と2回目以降の入力を同じ場所へ書けます。入力してから判定するという実際の手順と、プログラムの形が一致しやすくなります。

図2:解除コードを入力してから継続を判断する流れ

この図から分かること

do~while文では、最初に解除コードを入力してから一致しているかを確認します。

不一致の場合は継続条件が真になり、入力処理へ戻ります。一致すると条件が偽になり、ループを終了して次の処理へ進みます。

正解するまで計算問題を繰り返す

次のプログラムでは、864 + 279の答えを正しく入力するまで質問を繰り返します。

正しい計算結果が入力されるまで質問するプログラム

ファイル名:9_7_2.c

#include <stdio.h>

int main(void)
{
    int answer;
    const int first = 864;
    const int second = 279;
    const int correct = first + second;

    do {
        printf("%d + %d の答えを入力してください > ",
               first, second);
        scanf("%d", &answer);
    } while (answer != correct);

    printf("正しい結果を入力しました。\n");

    return 0;
}
実行結果の例
864 + 279 の答えを入力してください > 1100
864 + 279 の答えを入力してください > 1143
正しい結果を入力しました。
プログラムの詳しい解説

計算に使う2つの整数は、変更しない値として定義しています。

const int first = 864;
const int second = 279;

正解は、2つの整数を加算して求めます。

const int correct = first + second;

doブロックに質問と入力処理があるため、問題は必ず1回表示されます。

入力後は、次の条件を評価します。

answer != correct

入力した答えが正解と異なる間は、条件が真なので質問を繰り返します。

1143が入力されると条件が偽になり、do~while文を終了します。このプログラムでは不正解メッセージを表示していませんが、条件が真である間は同じ問題が再び表示されます。

続行確認にもdo~while文が使いやすい

do~while文は、処理を実行した後に、もう一度行うかを利用者へ尋ねる場面にも向いています。

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

do {
    計算する;
    結果を表示する;
    続けるか入力する;
} while (続行する条件);

この構成では、次の順序がそのままコードに表れます。

  1. 最初の計算を行う
  2. 計算結果を表示する
  3. 続行するか確認する
  4. 続行する場合は最初の計算へ戻る
  5. 続行しない場合は終了する

身長から適正体重を繰り返し計算する

次のプログラムでは、入力された身長からBMIが22となる適正体重を計算します。

計算後にyを入力すると、別の身長でもう一度計算します。y以外を入力すると終了します。

適正体重は次の式で求めます。

適正体重 = 身長(m) × 身長(m) × 22
続行確認をしながら適正体重を計算するプログラム

ファイル名:9_7_3.c

#include <stdio.h>

int main(void)
{
    double height_cm;
    double height_m;
    double standard_weight;
    char again;

    do {
        printf("身長を入力してください(cm)> ");
        scanf("%lf", &height_cm);

        height_m = height_cm / 100.0;
        standard_weight = height_m * height_m * 22.0;

        printf("BMIが22となる適正体重は%.2f kgです。\n",
               standard_weight);

        printf("別の身長でも計算しますか(y/n)> ");
        scanf(" %c", &again);
    } while (again == 'y');

    printf("計算を終了します。\n");

    return 0;
}
実行結果の例
身長を入力してください(cm)> 170.0
BMIが22となる適正体重は63.58 kgです。
別の身長でも計算しますか(y/n)> y
身長を入力してください(cm)> 160.0
BMIが22となる適正体重は56.32 kgです。
別の身長でも計算しますか(y/n)> n
計算を終了します。
プログラムの詳しい解説

身長は小数を含む可能性があるため、double型で扱います。

double height_cm;

double型の変数へscanfで入力するときは、変換指定子%lfを使います。

scanf("%lf", &height_cm);

入力された身長はcm単位なので、100.0で割ってm単位へ変換します。

height_m = height_cm / 100.0;

適正体重は、身長を2回掛けてから22.0を掛けて求めます。

standard_weight = height_m * height_m * 22.0;

計算結果を表示した後、続行するかをchar型のagainへ入力します。

scanf(" %c", &again);

%cの前にある空白には、入力バッファに残っている改行などの空白文字を読み飛ばす役割があります。

最後にagainがyであるかを調べます。

while (again == 'y');

yなら条件が真になり、身長の入力へ戻ります。nなど、y以外の文字が入力されると条件が偽になり、ループを終了します。

図3:続行確認とscanfの空白の役割

この図から分かること

do~while文では、計算と結果表示を行った後に続行確認を置けます。yが入力された場合だけループの先頭へ戻り、それ以外の文字なら終了します。

また、数値入力後にはEnterによる改行が入力バッファに残ることがあります。scanfで%cを使うときに変換指定子の前へ空白を置くことで、残った改行を読み飛ばしてからyやnを読み取れます。

BMIの判定と適正体重との差を表示する

次のプログラムでは、BMIを計算して判定結果を表示します。さらに、BMIが22となる適正体重との差も表示します。

計算後にyを入力すると、別の身長と体重でもう一度計算します。

BMIの判定基準は次のとおりです。

BMI判定
18.5未満低体重
18.5以上25.0未満普通体重
25.0以上30.0未満肥満1度
30.0以上35.0未満肥満2度
35.0以上40.0未満肥満3度
40.0以上肥満4度
BMIと適正体重との差を繰り返し表示するプログラム

ファイル名:9_7_4.c

#include <stdio.h>

int main(void)
{
    double height_cm;
    double height_m;
    double weight;
    double bmi;
    double standard_weight;
    double difference;
    const char *category;
    char again;

    do {
        printf("身長を入力してください(cm)> ");
        scanf("%lf", &height_cm);

        printf("体重を入力してください(kg)> ");
        scanf("%lf", &weight);

        height_m = height_cm / 100.0;
        bmi = weight / (height_m * height_m);
        standard_weight = height_m * height_m * 22.0;
        difference = weight - standard_weight;

        if (bmi < 18.5) {
            category = "低体重";
        } else if (bmi < 25.0) {
            category = "普通体重";
        } else if (bmi < 30.0) {
            category = "肥満(1度)";
        } else if (bmi < 35.0) {
            category = "肥満(2度)";
        } else if (bmi < 40.0) {
            category = "肥満(3度)";
        } else {
            category = "肥満(4度)";
        }

        printf("判定:%s\n", category);
        printf("BMI:%.2f\n", bmi);
        printf("適正体重との差:%+.2f kg\n", difference);

        printf("もう一度計算しますか(y/n)> ");
        scanf(" %c", &again);
    } while (again == 'y');

    printf("プログラムを終了します。\n");

    return 0;
}
実行結果の例
身長を入力してください(cm)> 170.0
体重を入力してください(kg)> 70.0
判定:普通体重
BMI:24.22
適正体重との差:+6.42 kg
もう一度計算しますか(y/n)> n
プログラムを終了します。
プログラムの詳しい解説

BMIは、体重を身長の2乗で割って求めます。

bmi = weight / (height_m * height_m);

適正体重は、身長の2乗に22.0を掛けて求めます。

standard_weight = height_m * height_m * 22.0;

現在の体重と適正体重との差は、次の式で計算します。

difference = weight - standard_weight;

differenceが正なら適正体重より重く、負なら適正体重より軽いことを表します。

BMIの範囲判定には、if~else if~elseを使用しています。

if (bmi < 18.5) {
    category = "低体重";
} else if (bmi < 25.0) {
    category = "普通体重";
}

条件は上から順番に評価されます。たとえばBMIが24.22の場合、bmi < 18.5は偽ですが、次のbmi < 25.0が真になるため、普通体重が選ばれます。

適正体重との差は、%+.2fを使って表示しています。

printf("適正体重との差:%+.2f kg\n", difference);

+フラグを指定すると、正の値にも+が表示されます。

  • 正の値の例:+6.42
  • 負の値の例:-3.20

計算結果を表示した後、againへyまたはnを入力します。againがyである間だけ、doブロックへ戻って計算を繰り返します。

do~while文を書くときの確認ポイント

do~while文を書くときは、次の点を確認すると安全です。

  • doブロックが最低1回実行されても問題ないか
  • 継続条件が続ける条件になっているか
  • 終了するために必要な変数がループ内で更新されているか
  • whileの後ろにセミコロンがあるか
  • char型の入力で改行を読み飛ばす必要があるか
  • y以外をすべて終了としてよいか
  • 入力、処理、続行確認の順番が自然になっているか

do~while文は、まず処理を行い、その結果を見て続けるか決めるループです。入力受付やメニュー表示、計算後の続行確認など、最初の1回が必ず必要な処理に使うと、プログラムの流れを素直に表現できます。