Menu

C言語の do-while ループ: 構文、例、使いどころ

C言語の本体優先のループ: do-while が判定の前に1回の実行を保証する仕組み、なぜセミコロンで終わるのか、そのために作られたメニューと再試行のパターン、そして普通の while ループとの違い。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

必ず1回は実行されるループ

while ループは動く前に判定するので、0回で終わることがあります。たいていはそれが正解です。しかしときには、まさにそれが誤りになります。プロンプトを表示してみるまで、それを繰り返すべきかどうかは分かりませんし、ユーザーの入力を何か読むまで、その良し悪しを判断できません。do-while は判定を末尾に移すので、本体が先に実行され、条件はもう一度やるかどうかだけを決めます。

条件 i < 5 は最初から偽です。while ループは0回、do-while はちょうど1回実行されます。両者の違いはそれがすべてです。

構文と、あのセミコロン

do {
    // 本体 - 必ず1回は実行される
} while (condition);

この順序は実行される順のまま読めます。本体を実行し(do)、条件がまだ成り立つ間は(while)、もう一度実行する、というわけです。

閉じかっこの後の末尾のセミコロンは必須です。do ... while (cond); は1つの文であり、C言語の文はセミコロンで終わります。省くとコンパイラは読み続け、その後のどこかで構文エラーを報告します - だからこそ、本当の間違いはエラーが指す行から何行も離れていることがよくあるのです。

ここは、C言語の中で while (cond); のセミコロンがバグではなく正しい唯一の場所でもあります。普通の while ループで同じ句読点を書くと空の本体になり、たいていは無限ループですが、ここでは do を閉じているのです。

本体が1文なら波かっこは省略できますが、他のあらゆるC言語の制御構造と同じく、それでも書きましょう。

入力検証のパターン

これこそ do-while が設計された用途です。受け入れられるかどうかを判断する前に何かを読まなければならないので、読み取りが判定の前に来る必要があります:

このループは値が通るまで読み続け、悪い値をはねるのと同じ条件が、もう一度の実行を要求します。while として書くと、読み取りは2回現れなければなりません - 条件を成立させるためにループの前に1回、本体の末尾に1回 - この重複こそ do-while が取り除くものです。

実際の入力なら、本体は代わりに scanf を呼ぶでしょう:

int age;
do {
    printf("年齢を入力してください (1-120): ");
    if (scanf("%d", &age) != 1) {
        while (getchar() != '\n') { }   /* 不正な行を捨てる */
        age = -1;                        /* もう一度実行させる */
    }
} while (age < 1 || age > 120);

行の残りを読み捨てる内側の while に注目してください。scanf が変換に失敗すると、問題のテキストは入力バッファに残ったままで、その後の読み取りもすべてそこで失敗します - プロンプトを出し続けて永遠に回るループです。それをクリアすることもこのパターンの一部なのです。

メニューのパターン

もう1つの定番の用途です。選択肢を表示し、選択を読み、それに応じて動作し、ユーザーが終了するまで繰り返します。判定すべき選択が存在する前に、メニューが現れなければなりません。

switch の中の break は switch を終わらせるのであって、ループを終わらせるのではありません - 両方が同じキーワードを使うので、ここは正確に述べる価値があります。ここでループが終わるのは choice != 4 が偽になるからです。switch の中からループを抜けたいなら return かフラグ変数が方法で、break だけではできません。

保証された最初の1回がバグになることもある

本体がどんな判定よりも先に実行されるため、do-while は存在しないデータを平気で処理してしまいます:

/* バグ: n が 0 でも a[0] を表示してしまう */
int i = 0;
do {
    printf("%d\n", a[i]);
    i++;
} while (i < n);

n == 0 のとき、これは空の配列の a[0] を読みます - 未定義動作です。空になり得るコレクションを走査するループには、判定が先に来る whilefor がふさわしいのです。

目安のルール: 反復回数が0になることが問題の性質上ありえないときにだけ do-while を使い、単に実際には起きにくいという理由では使わないこと。ユーザーへの入力要求、目標が出るまでサイコロを振る、候補を生成して判定する - これらは本当に最初の1回より前には判断できません。リストを歩くことにはそれが言えません。

do-while の中の break と continue

どちらも動きますし、continue には知っておく価値のあるひねりがあります。本体の先頭ではなく、条件の判定へ飛ぶのです。

本体の先頭にある i++ は、continue が途中で切り上げた回も含めて毎回実行されるので、ループはちゃんと進みます。更新を continue後ろに置くとループは止まってしまいます - while ループが持つのと同じ罠です。

break は即座にループを離れ、条件をまったく飛ばします。

3つのループから選ぶ

C言語の3つのループは能力としては同等です。選択は、どれが意図を言い表すかの問題です。

for        カウンタと上限と刻みがひとまとまりになる - 「n 回」
while      条件が変わるまで繰り返す。1回もないかもしれない - 「〜まで」
do-while   同じだが、最初の1回は保証される - 「少なくとも1回」

実際には do-while は3つの中で圧倒的に珍しいものです。ほとんどのループは数を数えるか、空の場合を扱う必要があるかで、そのどちらも判定が先頭にあることを求めます。while ループの条件を成立させるために、その直前で文を重複させている自分に気づいたら do-while に手を伸ばしましょう - その重複が合図です。

よくある質問

C言語で do-while ループはどう書きますか?

do { 本体 } while (条件); です - 本体が先、判定が後で、文全体がセミコロンで終わります。本体は必ず1回は実行され、その後は条件が非ゼロである限り繰り返されます。

C言語の while と do-while の違いは何ですか?

判定の位置です。while ループは最初の実行の前に条件を調べるので、0回で終わることがあります。do-while は後で調べるので、必ず1回は実行されます。その「保証された最初の1回」が本当に問題に必要なときにだけ do-while を選びましょう。

do-while ループの最後にセミコロンが必要なのはなぜですか?

do ... while (cond); は1つの文であり、他のあらゆるC言語の文と同じくセミコロンで終端されるからです。省くと、コンパイラは文の続きを読もうとするため、次の行を指す分かりにくい構文エラーになります。

do-while ループはいつ使うべきですか?

繰り返すかどうかを判断できるようになる前に、本体を実行しなければならないときです。入力を読む前にメニューを表示する、入力が正しくなるまで聞き直す、値を生成してから判定する、といった場合です。条件を最初に調べられるなら、while ループのほうが素直に意図を表します。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める