最低1回は本体が実行されるループがdo-while
です。
ユーザー入力の確認やメニューの表示など、まず1回やってみてから続行可否を決めたい場面で威力を発揮します。
「先に処理、後で判定」という流れを自然に書けるため、while
やfor
では少し書きづらいケースをシンプルに表現できます。
do-whileとは(最低1回実行のループ)
初心者向けの概要
do-whileは「最低1回は必ず本体が実行される」後判定ループです。
先にdo { ... }
の中身を実行し、最後にwhile (条件);
で繰り返し続行の可否を判断します。
初回に限っては条件が偽でも本体が1回は走る点が、前判定のwhile
と決定的に異なります。
最低1回実行の意味
初期状態がまだ「妥当か不明」でも、とりあえず1回処理して様子を見る、そんな設計に向いています。
ユーザーにメニューを見せる、値を入力してもらう、といった「まず提示→判断」の流れを自然に表現できます。
他のループとの位置づけ
回数が決まっているならfor
、条件を満たす間だけ前判定で回したいならwhile
、最低1回は実行してから判断したいならdo-while
が基本的な使い分けです。
意図に合う構文を選ぶと可読性が上がります。
do(本体)→while(条件)の流れ
処理の順序はdo
ブロック→while(条件)
の順です。
毎回「本体を実行してから」次を行うか判断します。
フローチャートでは「処理→条件判定→真なら再度処理、偽なら終了」となります。
前判定のwhile
は「条件判定→処理」なので真逆です。
どんな場面で使うか(入力確認・メニュー)
典型例は以下です。
いずれもまず1回は見せる/聞くことが重要です。
- メニュー表示と選択受付
- ユーザー入力の確認と再入力促し
- 繰り返し実験の1回目を必ず実行してから継続可否を決める
「1回は実行」こそが価値なので、初回スキップが許されない場面に向いていると覚えておくと選択しやすくなります。
do-whileの構文と使い方)
基本構文
do-whileの形はシンプルで、末尾の;
が必須です。
#include <stdio.h>
int main(void) {
// ここでループ制御に使う変数を用意します
int 続ける = 1; // 1なら続行、0なら終了
do {
// ループ本体: 少なくとも1回は実行されます
printf("本体を実行しています。\n");
// ここで続行可否を更新します(例では1回でやめる)
続ける = 0;
} while (続ける); // ← do-whileは末尾のセミコロンが必要
return 0;
}
末尾のwhile (条件);
の;
を絶対に忘れないでください。
これを落とすとコンパイルエラーになります。
さらに条件を更新する処理をdo
ブロックの中で必ず行うことが、無限ループを避けるための基本です。
サンプルコード1(メニューを表示して繰り返す)
典型的なメニュー処理はdo-whileで読みやすく書けます。
まず1回メニューを表示し、選択に応じて分岐、終了選択なら抜ける流れです。
#include <stdio.h>
/*
* シンプルなメニューを表示して、3(終了)が選ばれるまで繰り返します。
* 入力が数値であることは前提(詳細な検証はサンプル2で扱います)。
*/
int main(void) {
int choice; // ユーザーの選択
do {
// メニューの表示(毎回1回は見える)
printf("\n==== メニュー ====\n");
printf("1) 足し算のデモ\n");
printf("2) 引き算のデモ\n");
printf("3) 終了\n");
printf("番号を選んでください: ");
// 選択の入力(簡単のためエラーチェックは省略)
if (scanf("%d", &choice) != 1) {
// 数字以外が来たときの簡易的な掃除
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) { /* バッファを捨てる */ }
printf("数値を入力してください。\n");
choice = 0; // 不正値として扱う
continue; // メニューに戻る
}
// 選択に応じた処理
switch (choice) {
case 1: {
int a = 2, b = 3;
printf("%d + %d = %d\n", a, b, a + b);
break;
}
case 2: {
int a = 5, b = 2;
printf("%d - %d = %d\n", a, b, a - b);
break;
}
case 3:
printf("終了します。\n");
break;
default:
printf("不正な選択です。1〜3を入力してください。\n");
}
} while (choice != 3); // 3が選ばれるまで繰り返す(末尾セミコロンに注意)
return 0;
}
==== メニュー ====
1) 足し算のデモ
2) 引き算のデモ
3) 終了
番号を選んでください: 1
2 + 3 = 5
==== メニュー ====
1) 足し算のデモ
2) 引き算のデモ
3) 終了
番号を選んでください: 3
終了します。
最初のメニュー表示が必ず1回実行されるため、初期化の都合で初回がスキップされる心配がありません。
「見せてから判断」の定型にぴったりです。
サンプルコード2(入力が正しいまで繰り返す)
ユーザーに範囲内の整数を入力してもらい、不正ならメッセージを出して再入力を促す例です。
数字以外が入力されたときに備えて、入力バッファの掃除も行います。
#include <stdio.h>
/*
* 1〜100の整数を受け付けます。
* 数字以外や範囲外の場合は理由を伝えて再入力させます。
*/
int main(void) {
int value;
int ok = 0; // 妥当なら1にするフラグ
do {
printf("1〜100の整数を入力してください: ");
int ch; // 入力バッファ掃除用
if (scanf("%d", &value) != 1) {
// 数字以外が入力された場合
printf("数値ではありません。やり直してください。\n");
while ((ch = getchar()) != '\n' && ch != EOF) { /* 余分な入力を捨てる */ }
ok = 0;
} else if (value < 1 || value > 100) {
// 数値だが範囲外
printf("範囲外です。1〜100で入力してください。\n");
ok = 0;
} else {
// 妥当
ok = 1;
}
} while (!ok); // 妥当になるまで繰り返す
printf("受け付けました: %d\n", value);
return 0;
}
1〜100の整数を入力してください: abc
数値ではありません。やり直してください。
1〜100の整数を入力してください: 150
範囲外です。1〜100で入力してください。
1〜100の整数を入力してください: 42
受け付けました: 42
do-whileなら「1回聞いて、ダメならまた聞く」を素直に書けます。
入力系ではこの形がもっとも読みやすいことが多いです。
do-whileとwhileの違い
条件評価のタイミング
do-whileは後判定、whileは前判定です。
これが初回実行有無の差を生みます。
以下に要点を整理します。
観点 | do-while | while |
---|---|---|
条件評価のタイミング | 本体の後 | 本体の前 |
初回実行の保証 | あり(必ず1回) | なし(条件が偽なら0回) |
典型的な用途 | 入力確認、メニュー | 条件を満たす間の処理全般 |
文の終端 | while(条件); と末尾にセミコロン必須 | while(条件) { … } 末尾にセミコロンは不要 |
「いつ判定するか」を意識して選ぶと、ロジックが明快になります。
末尾セミコロンの有無は構文エラーの温床なので特に注意しましょう。
条件が偽のときの初回実行
条件が最初から偽でも、do-whileは本体が1回だけ実行されます。
#include <stdio.h>
int main(void) {
int x = 10;
do {
printf("このメッセージは必ず1回は表示されます。\n");
} while (x < 0); // 最初から偽
return 0;
}
このメッセージは必ず1回は表示されます。
一方while (x < 0) { ... }
なら1回も実行されません。
初回実行が必要か否かが選択基準です。
書き換え例
do-whileで書かれた処理をwhile
に書き換える定番パターンを示します。
意図が「最低1回」なら、do-whileが最短で明確ですが、プロジェクト方針によっては前判定に揃えたい場合もあります。
例1: センチネル初期値を使う
// do-while版
int choice;
do {
// ... メニュー表示と入力 ...
} while (choice != 3);
// while版(センチネル)
int choice = -1; // 3以外に初期化して初回実行を保証
while (choice != 3) {
// ... メニュー表示と入力 ...
}
例2: 無限ループ + break
// do-while版
int ok;
do {
// ... 入力と検証 ...
} while (!ok);
// while版(無限ループ+break)
while (1) {
// ... 入力と検証 ...
if (ok) break; // 妥当になったら脱出
}
例3: 前読み(priming read)パターン
// while版(前読み)
int value;
printf("入力してください: ");
scanf("%d", &value); // 最初に1回読む
while (!is_valid(value)) {
printf("やり直してください: ");
scanf("%d", &value);
}
書き換え自体は可能ですが、読みやすさはケースバイケースです。
特に「メニュー」「入力検証」ではdo-whileの方が意図が直感的に伝わります。
注意点とよくあるミス
whileの末尾セミコロン(;)を忘れない
do-whileは末尾のwhile (条件);
の;
が必須です。
これを忘れるとコンパイルエラーになります。
// 正しい
do {
/* 本体 */
} while (cond); // ← セミコロンあり
// 誤り(コンパイルエラー)
do {
/* 本体 */
} while (cond) // ← セミコロンなし
逆に、while (条件)
ループ単体では末尾にセミコロンを付けてはいけません。
勘違いしてwhile (cond);
と書くと「空ループ」になり、意図せず固まります。
// while単体での誤り: 本体が空の無限ループになり得る
while (cond); // ← このセミコロンは不要かつ危険
{
/* ここはループの本体ではない(別ブロック扱い) */
}
無限ループを避ける条件の書き方
「ループ条件を変化させる更新」が本体に必ず存在するようにします。
入力待ちなら毎回scanf
する、カウンタなら増減する、フラグなら状況に応じて切り替える等です。
比較==
と代入=
の書き間違いにも注意してください。
// 悪い例: 条件を変化させない
int count = 0;
do {
printf("count=%d\n", count);
// countを変えていない → 無限ループ
} while (count < 3);
// 良い例: 更新する
int count2 = 0;
do {
printf("count2=%d\n", count2);
count2++; // 更新
} while (count2 < 3);
「条件がいつ偽になるか」を、コードを読んで即答できる形にするのが安全です。
変数の初期化と更新の位置
初期化はループ前、更新はループ内が基本です。
ループ内で毎回初期化してしまうと進捗がリセットされ、終了条件に到達できません。
// 悪い例: ループ内で毎回初期化してしまう
int sum = 0;
int i = 0;
do {
i = 0; // ← ここでリセットしてしまうためiが進まない
sum += i;
i++;
} while (i < 3);
// 良い例: 初期化は前、更新は内側
int sum2 = 0;
int j = 0;
do {
sum2 += j;
j++; // ちゃんと進む
} while (j < 3);
printf("sum2=%d\n", sum2); // 0+1+2 = 3
どの変数がループ制御を担うかを明示し、その寿命を意識して配置するとミスが減ります。
複雑にしすぎない(シンプルに書く)
条件式が長くなりがちな場合は、途中結果を説明的な名前の変数に分解しましょう。
break
やcontinue
も使えますが、多用して制御が飛び交うと読みづらくなるため、まずは「ループ条件を正しく保つ」基本を優先します。
必要なら小さな関数に分けると意図が伝わりやすくなります。
まとめ
do-whileは「必ず1回は本体を実行してから継続を判定する」後判定ループです。
メニュー表示や入力検証のように「まず提示/取得→判定→必要なら再実行」という流れを自然に書けます。
前判定のwhile
との違いは条件評価のタイミングで、初回実行の保証が必要ならdo-whileを選ぶとコードが簡潔になります。
末尾セミコロンの付け忘れや条件更新漏れに注意しつつ、「いつ偽になるか」を常に意識したシンプルなループ設計を心がけてください。