C言語で繰り返し処理を学ぶとき、多くの方はfor文やwhile文から勉強を始めます。
しかし実務や問題演習では、「最低1回は必ず処理を実行したい」という場面もよくあります。
このようなときに活躍するのがdo-while文です。
本記事では、C言語初心者の方でも理解しやすいように、do-while文の基本から具体例、注意点、他のループとの使い分けまで詳しく解説します。
do-while文とは何か
do-while文の基本構文と書き方
do-while文は、「少なくとも1回は処理を実行してから条件判定を行う」という特徴を持つループ構文です。
一般的な書き方は次のようになります。
#include <stdio.h>
int main(void) {
int i = 0; // カウンタ変数の初期化
// do-while文の基本構文
do {
// ここに繰り返したい処理を書く
printf("i = %d\n", i);
// 繰り返しごとに変数を更新する
i++;
} while (i < 5); // 条件式の最後にセミコロン(;)が必要
return 0;
}
i = 0
i = 1
i = 2
i = 3
i = 4
do-while文の構造を文章で整理すると、次のような順番で処理されます。
- doブロック内の処理を実行する。
- ブロックの後に続く
while(条件式)を評価する。 - 条件式が
真(1)なら、再びdoブロックに戻って処理を繰り返す。 - 条件式が
偽(0)なら、ループを終了する。
特に「条件判定が後ろにある」ことが、他のループ構文との大きな違いです。
while文との違い
C言語のwhile文は、「条件を先に判定してから処理を行う」ループです。
while文とdo-while文の違いを、構文の形で比較してみましょう。
| 構文 | 処理の流れ | 最低実行回数 |
|---|---|---|
| while文 | 条件判定 → 本体の処理 | 0回以上 |
| do-while文 | 本体の処理 → 条件判定 | 1回以上 |
while文の例は次のようになります。
#include <stdio.h>
int main(void) {
int i = 0;
// while文の基本構文
while (i < 5) { // ここで最初に条件判定を行う
printf("i = %d\n", i);
i++;
}
return 0;
}
このwhile文と、先ほど示したdo-while文は、今回の例では同じ結果を出力します。
しかし「最初の条件判定の結果によって、1回も実行されない可能性があるかどうか」が大きな違いとなります。
具体的には、iの初期値を5にして比較してみると差が分かりやすくなります。
この違いは次の章で詳しく説明します。
do-while文の動き方を具体例で理解
繰り返し回数が0回にならない理由
do-while文は「必ず1回は処理を実行してから条件を判定する」という仕様になっています。
そのため、たとえ条件式が最初から偽であっても、処理が1回だけ実行されます。
次のコードで、while文とdo-while文の違いを実際に比較してみます。
#include <stdio.h>
int main(void) {
int x = 10;
printf("=== while文の場合 ===\n");
// 条件が最初から偽(x < 5は偽)のwhile文
while (x < 5) {
printf("while: x = %d\n", x);
x++;
}
printf("=== do-while文の場合 ===\n");
x = 10; // xを10に戻す
// 条件が最初から偽(x < 5は偽)のdo-while文
do {
printf("do-while: x = %d\n", x);
x++;
} while (x < 5);
return 0;
}
想定される実行結果は次のようになります。
=== while文の場合 ===
=== do-while文の場合 ===
do-while: x = 10
この結果から分かるように、while文ではx < 5が最初から偽なので1回も処理が実行されません。
一方、do-while文では条件が偽であっても「doブロック内が1回実行された後に」条件が評価されるため、少なくとも1回は処理が実行されるのです。
ユーザー入力を使ったdo-while文のサンプルコード
do-while文は、ユーザーに何度か入力をさせたいような場面で特に役立ちます。
例えば、ユーザーに数値を入力してもらい、0が入力されるまで合計を計算し続けるプログラムを考えてみます。
#include <stdio.h>
int main(void) {
int num; // ユーザーから入力された数値
int sum = 0; // 合計値を保存する変数
printf("整数を入力してください(0で終了します)。\n");
// 少なくとも1回は入力を受け付けたいのでdo-while文を使用
do {
printf("数値を入力: ");
scanf("%d", &num); // ユーザーから整数を読み込む
sum += num; // 入力された数値を合計に加算する
} while (num != 0); // 0が入力されるまで繰り返す
printf("合計値は%dです。\n", sum);
return 0;
}
このプログラムの動き方を文章で整理すると、次のようになります。
- ユーザーに数値の入力を求める。
- 入力された数値を合計値に加算する。
- 入力が0でなければ、再び入力を求める。
- 0が入力されたらループを抜けて、合計値を表示する。
実行例は次のようなイメージです。
整数を入力してください(0で終了します)。
数値を入力: 10
数値を入力: 3
数値を入力: -2
数値を入力: 0
合計値は11です。
このように、「とにかく1回はユーザーに入力させたい」という場面では、do-while文が非常に自然に書けます。
無限ループを避けるための注意ポイント
do-while文に限らず、ループ処理では無限ループに注意する必要があります。
無限ループとは、終了条件が永遠に満たされず、プログラムが止まらない状態のことです。
do-while文で無限ループを避けるための主なポイントは次のようになります。
1つ目は、条件式に使っている変数をループ内で必ず更新することです。
例えば、次のコードは典型的な無限ループ例です。
#include <stdio.h>
int main(void) {
int i = 0;
// 悪い例: iが更新されないので無限ループになる
do {
printf("i = %d\n", i);
// i++; // この更新がないと、条件がずっと真のままになる
} while (i == 0);
return 0;
}
2つ目は、ユーザー入力に依存した終了条件の場合、入力を正しく読み取れているかに注意することです。
たとえばscanfが失敗したときにループが終わらなくなるケースがありますが、これは少し発展的な内容なので、まずは「条件に使う変数をきちんと変化させる」というポイントを確実に押さえておくとよいです。
do-while文を使うと便利な場面
入力チェック(バリデーション)でのdo-while文の使い方
プログラムでは、「ユーザーが正しい値を入力するまで繰り返し入力させる」という処理がよく登場します。
これを入力チェック(バリデーション)と呼びます。
例えば、0〜100の範囲の点数だけを受け付けるプログラムを考えてみます。
#include <stdio.h>
int main(void) {
int score;
// 正しい値が入力されるまで繰り返す
do {
printf("点数を入力してください(0〜100): ");
scanf("%d", &score);
// 範囲外のときはメッセージを表示して再入力させる
if (score < 0 || score > 100) {
printf("入力が不正です。0〜100の範囲で入力してください。\n");
}
} while (score < 0 || score > 100); // 条件式に同じ判定を書く
printf("入力された点数は%d点です。\n", score);
return 0;
}
想定される実行例は次のようになります。
点数を入力してください(0〜100): 150
入力が不正です。0〜100の範囲で入力してください。
点数を入力してください(0〜100): -5
入力が不正です。0〜100の範囲で入力してください。
点数を入力してください(0〜100): 80
入力された点数は80点です。
このように、「1回は必ず入力を受け付け、その結果をチェックして、ダメならやり直す」という流れは、do-while文の構造と非常に相性が良いです。
メニュー選択処理でのdo-while文の使い方
コンソールプログラムでよくあるパターンとして、メニューを表示してユーザーに選択させる処理があります。
例えば簡単なメニューを作ると、次のようなコードになります。
#include <stdio.h>
int main(void) {
int choice;
do {
printf("\n=== メニュー ===\n");
printf("1: 足し算\n");
printf("2: 引き算\n");
printf("3: 終了\n");
printf("番号を選んでください: ");
scanf("%d", &choice);
if (choice == 1) {
printf("足し算を選びました。\n");
// ここに足し算の処理を書くことができます
} else if (choice == 2) {
printf("引き算を選びました。\n");
// ここに引き算の処理を書くことができます
} else if (choice == 3) {
printf("終了を選びました。\n");
} else {
printf("不正な選択です。1〜3の番号を入力してください。\n");
}
} while (choice != 3); // 3が選ばれるまでメニューを繰り返す
printf("プログラムを終了します。\n");
return 0;
}
実行のイメージは次のようになります。
=== メニュー ===
1: 足し算
2: 引き算
3: 終了
番号を選んでください: 5
不正な選択です。1〜3の番号を入力してください。
=== メニュー ===
1: 足し算
2: 引き算
3: 終了
番号を選んでください: 1
足し算を選びました。
=== メニュー ===
1: 足し算
2: 引き算
3: 終了
番号を選んでください: 3
終了を選びました。
プログラムを終了します。
このような「メニュー表示 → 入力 → 処理 → 必要なら再びメニューへ」という流れは、do-while文の典型的な活用パターンです。
while文やfor文では書きにくいケースとの比較
do-while文を使わなくても、while文やfor文を使えば、同様の処理を書くことは原理的には可能です。
しかし、「最低1回は処理を行う」という要件がある場合、while文やfor文ではどうしても同じ処理を2回書かなければならないことがあります。
例として、先ほどのメニュー処理をwhile文で書いてみます。
#include <stdio.h>
int main(void) {
int choice = 0;
// while文で書く場合の一例
while (choice != 3) {
printf("\n=== メニュー ===\n");
printf("1: 足し算\n");
printf("2: 引き算\n");
printf("3: 終了\n");
printf("番号を選んでください: ");
scanf("%d", &choice);
if (choice == 1) {
printf("足し算を選びました。\n");
} else if (choice == 2) {
printf("引き算を選びました。\n");
} else if (choice == 3) {
printf("終了を選びました。\n");
} else {
printf("不正な選択です。1〜3の番号を入力してください。\n");
}
}
printf("プログラムを終了します。\n");
return 0;
}
この書き方でも動作はしますが、「最初にchoiceを何にしておくか」を意識しなければなりませんし、条件の書き方によっては最初にメニューが表示されないようなバグを生む可能性もあります。
一方、do-while文なら、「まずやること(メニュー表示と入力)」→「続けるかどうかの判定」という流れが素直に書けるため、意図がコードに現れやすく、ミスも減らせるという利点があります。
C言語初心者が押さえるべきdo-while文のポイント
条件式の書き方とセミコロンの付け忘れに注意
do-while文で最もよくあるミスの1つが、whileの後ろにセミコロンを書き忘れることです。
正しい形は次のようになります。
do {
// 処理
} while (条件式); // ← 最後に必ずセミコロンが必要
セミコロンを忘れると、コンパイルエラーや意図しない動作につながります。
例えば、次のような間違ったコードを考えてみます。
#include <stdio.h>
int main(void) {
int i = 0;
// セミコロンを書き忘れた例(コンパイルエラーになる)
do {
printf("i = %d\n", i);
i++;
} while (i < 3) // セミコロンがない
printf("ここまで来ました。\n");
return 0;
}
このような書き方は文法上正しくないので、コンパイラがエラーを報告します。
do-while文を書くときは、「while(…)の後ろにセミコロンを書く」というルールを、ぜひセットで覚えておいてください。
また、条件式自体はwhile文やfor文と同じく、整数値として評価される式であれば何でも書くことができます。
例えばi < 10やnum != 0、flag == 1などが代表的です。
フラグ変数と組み合わせた制御方法
少し慣れてきたら、do-while文とフラグ変数を組み合わせて制御する方法も知っておくと便利です。
フラグ変数とは、処理を続けるかどうかを表す目印として使う変数で、多くの場合0と1の2値をとります。
次は、ユーザーが'y'と入力したら処理を続ける、'n'なら終了する、という例です。
#include <stdio.h>
int main(void) {
int running = 1; // ループを続けるかどうかを表すフラグ(1:続行, 0:終了)
char ans;
do {
printf("処理を実行しました。\n");
printf("もう一度実行しますか?(y/n): ");
scanf(" %c", &ans); // 先頭の空白は前の改行文字を読み飛ばすため
if (ans == 'y' || ans == 'Y') {
running = 1; // もう一度実行する
} else {
running = 0; // 実行をやめる
}
} while (running == 1); // フラグ変数を条件式に使う
printf("終了します。\n");
return 0;
}
実行の流れとしては、処理 → 続けるか質問 → フラグを更新 → フラグを条件としてループ継続を判定という形になっています。
このようにフラグ変数を使うと、「ループを続けるかどうか」の判断基準を1か所にまとめられるので、あとから処理を拡張したり、条件を変更したりするのが楽になります。
他のループ(for, while)との使い分けの目安
最後に、for文・while文・do-while文の使い分けの目安を整理しておきます。
あくまで一般的な指針ですが、C言語初心者の方の判断基準として役立ちます。
| ループ構文 | 向いている場面 | 特徴 |
|---|---|---|
| for文 | 回数があらかじめ決まっている繰り返し(例: 10回繰り返す) | 初期化・条件・更新が1行にまとまっている |
| while文 | 「条件が真である間」処理したいが、0回の場合もありうる | 条件判定が先、0回実行の可能性がある |
| do-while文 | 「最低1回は実行したい」処理(入力、メニューなど) | 条件判定が後、必ず1回は実行される |
特にdo-while文を選ぶとよい典型パターンは、次のようなケースです。
1つ目は、ユーザーからの入力を最低1回は受け付けたいときです。
例として、合計計算や点数入力、メニューの選択などが挙げられます。
2つ目は、「処理 → 続けるかどうかの判定」という流れを分かりやすく書きたいときです。
この場合、do-while文を使うと、コードを読む人にとっても意図が伝わりやすくなります。
一方で、繰り返し回数がはっきり決まっている場合(例: 0から9までの配列要素を順番に処理するなど)は、for文の方が簡潔に書けて読みやすいことが多いです。
また、「条件が満たされないなら1回もやらない」という動きが自然な場合は、while文を使う方が適しています。
まとめ
do-while文は、「最低1回は必ず処理を実行し、その後条件次第で繰り返す」という特徴を持つループ構文です。
ユーザー入力やメニュー選択、入力チェックなど、現実的なプログラムで頻繁に登場するパターンに向いています。
while文やfor文との違いを意識しながら、セミコロンの付け忘れに注意しつつ、まずは簡単な入力プログラムから実際に書いて試してみると理解が深まります。
慣れてきたら、フラグ変数との組み合わせや他のループとの使い分けも意識して、状況に応じた最適なループ構文を選べるようになることを目指してください。
