閉じる

【C言語】 do-while文入門|while文との違いと初心者がハマる落とし穴

C言語のdo-while文は、必ず1回は処理が実行されるという特徴を持つ繰り返し構文です。

while文とよく似ていますが、評価タイミングの違いから、初心者が思わぬバグを生みやすい構文でもあります。

本記事では、do-while文の基本から、while文との違い、よくある落とし穴、安全に使うためのコツまで、図解とサンプルコード付きで詳しく解説します。

do-while文とは?基本構文と特徴

do-while文の基本構文と書き方

まずは、do-while文の見た目とルールを整理します。

do-while文の基本構文は次のようになります。

C言語
#include <stdio.h>

int main(void) {
    int i = 0;  // カウンタ変数を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文の構文には3つの重要ポイントがあります。

1つ目は、必ずdo { ... } while (条件);という順番で書くことです。

while文のようにwhile (条件) { ... }とはならないので、順番を取り違えないようにします。

2つ目は、条件式の末尾にセミコロン;が必要であることです。

ここをよく付け忘れてコンパイルエラーになります

do-while文専用のルールだと意識してください。

3つ目は、繰り返しの本体となる処理がdo { ... }ブロックに書かれるという点です。

このブロックは少なくとも1回は実行されるため、「必ず1回はやりたい処理」をここに書くのが基本的な使い方になります。

while文との評価タイミングの違い

do-while文とwhile文は、ともに「条件が真なら繰り返す」という仕組みは共通ですが、条件式を評価するタイミングが決定的に異なります。

while文は前判定、do-while文は後判定のループです。

  • while文
    • ループに入るに条件をチェックします。
    • 最初から条件が偽なら、ブロック内の処理は1回も実行されません。
  • do-while文
    • ループので条件をチェックします。
    • 条件が最初から偽であっても、ブロック内の処理は最低1回実行されます。

この違いにより、同じような条件式を書いても、実際の動作が大きく変わることがあります。

特にユーザー入力を1回は受け取りたい場合などでは、do-while文の方が自然に書けることが多いです。

do-while文の実行回数が必ず1回以上になる理由

do-while文が必ず1回は実行されることを、コードで確認してみます。

C言語
#include <stdio.h>

int main(void) {
    int i = 10;  // すでに10なので、条件(i < 5)は最初から偽

    do {
        printf("このメッセージは必ず1回は表示されます。i = %d\n", i);
        i++;
    } while (i < 5);  // iは最初から10なので、ここは最初から偽

    printf("ループ終了後のi = %d\n", i);

    return 0;
}

実行結果は次のようになります。

実行結果
このメッセージは必ず1回は表示されます。i = 10
ループ終了後のi = 11

条件(i < 5)は、最初から偽です。

しかし、実際には1回だけメッセージが表示されています。

これは、条件判定が「処理ブロックの後」に行われるためです。

この性質は、次のような場面で特に役立ちます。

  • 少なくとも1回はメニューを表示したいとき
  • ユーザーからの入力を必ず1回は受け取りたいとき
  • ファイルからの読み込みなどを「1回やってみてから」続行するか決めたいとき

while文との違いを具体例で理解

while文との比較コード例

while文とdo-while文の違いを、同じような処理内容で比較してみます。

while文の例

C言語
#include <stdio.h>

int main(void) {
    int value;

    printf("0以外の数値を入力してください(0で終了します)。\n");
    scanf("%d", &value);

    // while文(前判定)の例
    while (value != 0) {
        printf("あなたが入力した値は %d です。\n", value);

        printf("もう一度入力してください(0で終了します)。\n");
        scanf("%d", &value);
    }

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

ユーザーが最初に0を入力した場合、while (value != 0)は最初から偽になり、ループ本体は1回も実行されません

do-while文の例

同じ処理をdo-while文で書き直した例です。

C言語
#include <stdio.h>

int main(void) {
    int value;

    // do-while文(後判定)の例
    do {
        printf("0以外の数値を入力してください(0で終了します)。\n");
        scanf("%d", &value);

        if (value != 0) {  // 0以外のときだけ表示
            printf("あなたが入力した値は %d です。\n", value);
        }
    } while (value != 0);  // 入力値が0ならループ終了

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

この場合は、ユーザーが最初に0を入力しても、一度は必ずプロンプトが表示されるため、インタラクティブな処理を書くときに自然な流れになります。

do-while文が向いているケース

do-while文が力を発揮するのは、「1回は必ずやりたい処理」があるループです。

代表的なケースを整理します。

1つ目は、メニューを表示して選択させる処理です。

メニュー画面は最低でも1回は見せる必要があり、入力内容によって繰り返し表示するかが決まるため、do-while文と相性が良いです。

2つ目は、再試行をユーザーに尋ねる処理です。

例えば「もう一度やりますか?(y/n)」のような確認を、少なくとも1回は行う場面では、do-while文を用いると読みやすくなります。

3つ目は、「1回試してから」継続するかどうかを判断する処理です。

ファイルオープンや通信処理など、まず試行してから結果に応じてループを続行するようなケースに向いています。

while文の方が適しているケースとの見分け方

一方で、必ずしもdo-while文が最適とは限りません

while文の方が自然になる場面も多くあります。

代表的なケースを整理した表です。

観点do-while文が向くケースwhile文が向くケース
初回実行最低1回は実行したい0回でも問題ない
典型例入力受付、メニュー表示範囲内ループ、配列処理
読みやすさ「1回やってから決める」流れ「やる前に条件を確認」する流れ
初期状態条件式に依存せず開始したい条件を満たすときだけ開始したい

コードを書いていて「この処理は0回でもよいのか?」と自問したとき、0回もあり得るならwhile文、必ず1回は行わないとおかしいならdo-while文、と判断すると整理しやすくなります。

初心者がハマるdo-while文の落とし穴

セミコロン(;)の付け忘れによるコンパイルエラー

do-while文特有の落とし穴として条件式の末尾セミコロン;の付け忘れがあります。

次のようなコードは、典型的なミスです。

C言語
#include <stdio.h>

int main(void) {
    int i = 0;

    do {
        printf("i = %d\n", i);
        i++;
    } while (i < 5)  // ← セミコロンを付け忘れた例

    return 0;
}

このように書くと、多くのコンパイラで「構文エラー」「expected ‘;’」のようなメッセージが出ます。

正しくは次のように;を付けます。

C言語
    } while (i < 5);  // ← 行末のセミコロンを忘れない

while文には;が付かないため、while文とdo-while文の混同からこのミスが発生しやすくなります。

「do-whileのwhileにはセミコロン」と、セットで覚えておくことをおすすめします。

条件式の書き方ミスによる無限ループ

do-while文に限った話ではありませんが、条件式のミスは無限ループの大きな原因です。

do-while文は「1回は必ず実行される」ため、その1回目で誤った状態になり、そのまま無限ループに入るケースもあります。

次のコードは、条件式の比較演算子を誤って書いた例です。

C言語
#include <stdio.h>

int main(void) {
    int i = 0;

    do {
        printf("i = %d\n", i);
        i++;

        // 本当は i < 5 と書きたかった
    } while (i = 5);  // ← 比較ではなく代入になっているミス

    return 0;
}

このコードではi = 5が「代入」になっており、条件式としては「5(真)」と評価されます。

そのため常に真になり無限ループが発生します。

本来書きたかったのは次のような比較です。

C言語
    } while (i < 5);  // 正しくは比較演算子<

条件式を書くときは、代入演算子=と比較演算子==<などを混同しないことが重要です。

変数の初期化忘れ・更新忘れ

ループに使う変数の初期化忘れ更新忘れも、do-while文でよく起きるミスです。

初期化忘れの例を見てみましょう。

C言語
#include <stdio.h>

int main(void) {
    int i;  // 初期化していない

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

    return 0;
}

変数iを初期化していないため、未定義の値からスタートしてしまいます。

これは動作が予測できない危険なバグです。

また、更新忘れの例も典型的です。

C言語
#include <stdio.h>

int main(void) {
    int i = 0;

    do {
        printf("i = %d\n", i);
        // i++ を書き忘れた
    } while (i < 5);  // i がずっと0のままなので、条件(i < 5)は永遠に真

    return 0;
}

このコードでは、iが更新されないため、i < 5がずっと真となり、無限ループになります。

ループを書くときは、「初期化・条件・更新」の3つがそろっているかを、毎回意識して確認すると安全です。

ブロック範囲とローカル変数のスコープの勘違い

do-while文の中で宣言した変数は、そのブロック{ }の中でのみ有効です。

このスコープの概念を勘違いすると、予期せぬコンパイルエラーやバグにつながります。

次のコードを見てください。

C言語
#include <stdio.h>

int main(void) {

    do {
        int x = 10;  // doブロック内のローカル変数
        printf("x = %d\n", x);
    } while (0);

    // ここでxを使おうとするとエラー
    // printf("外側でのx = %d\n", x);  // コンパイルエラー

    return 0;
}

xdo { ... }ブロック内だけで有効な変数です。

そのため、外側でxを使おうとすると、未宣言の変数としてエラーになります。

スコープのルールとして、「宣言したブロックを出たら、その変数は使えない」と覚えておくとよいです。

これはdo-while文に限らず、if文やfor文のブロックでも同様です。

フラグ変数の使い方を誤った条件分岐

do-while文では、「続けるかどうか」をフラグ変数で管理することがあります。

このとき、フラグの値や条件式を誤ると、意図しないループになります。

次のコードは、フラグ変数の扱いを誤った例です。

C言語
#include <stdio.h>

int main(void) {
    int continue_flag = 1;  // 1なら続行、0なら終了のつもり

    do {
        int input;

        printf("数値を入力してください(0で終了): ");
        scanf("%d", &input);

        if (input == 0) {
            continue_flag = 0;  // 終了したい
        }

        // ここで本来は、inputに応じた処理を行う

    } while (continue_flag = 1);  // ← 間違い: 代入にしてしまっている

    printf("終了しました。\n");
    return 0;
}

ここではcontinue_flag = 1が代入になっており、条件式としては常に真です。

そのため、フラグを0にしてもループが終わらないというバグが生じます。

正しくは比較演算子を使って次のように書きます。

C言語
    } while (continue_flag == 1);  // 比較にする

もしくは、フラグを0か1で扱うなら、while (continue_flag)のように「0以外なら真」とみなして書く方がシンプルな場合もあります。

do-while文を安全に使うためのコツ

無限ループを防ぐ条件設計のポイント

do-while文を安全に使うためには、無限ループを避ける条件設計が重要です。

条件設計のポイントを、文章で整理します。

まず、開始状態として、ループに入る前に変数をどの値にしておくかを明確にします。

例えばiを0から始めるのか、1から始めるのか、あるいはユーザー入力で決まるのかを意識します。

次に、更新として、ループの本体で変数をどのように変化させるのかを考えます。

加算、減算、入力の再取得など、状態が必ず変わる処理を入れることが重要です。

最後に、終了条件として、「どの状態になったらループをやめるのか」を条件式で正しく表現します。

条件が「狭すぎたり」「広すぎたり」すると、期待通りに終了しません。

この3つが論理的につながっているかを、紙に書き出して確認する習慣をつけると、無限ループをかなり防げます。

デバッグしやすい書き方とprintfによる確認

do-while文の挙動がわからなくなったときは、printfによるログ出力が非常に役立ちます。

次のように、ループ内で変数の値や分岐の状態を出力してみます。

C言語
#include <stdio.h>

int main(void) {
    int i = 0;

    do {
        printf("[DEBUG] ループ開始時のi = %d\n", i);  // デバッグ用出力

        // 実際の処理
        printf("処理中... i = %d\n", i);

        i++;  // 状態更新

        printf("[DEBUG] 更新後のi = %d\n", i);  // デバッグ用出力
    } while (i < 3);

    printf("ループ終了時のi = %d\n", i);
    return 0;
}
実行結果
[DEBUG] ループ開始時のi = 0
処理中... i = 0
[DEBUG] 更新後のi = 1
[DEBUG] ループ開始時のi = 1
処理中... i = 1
[DEBUG] 更新後のi = 2
[DEBUG] ループ開始時のi = 2
処理中... i = 2
[DEBUG] 更新後のi = 3
ループ終了時のi = 3

このように、ループの各段階で値を確認することで、「どこでおかしくなっているのか」を特定しやすくなります。

デバッグ用の[DEBUG]というプレフィックスを付けておくと、後でまとめて削除するときにも探しやすくなります。

while文と使い分けるための判断基準

最後に、do-while文とwhile文をどう使い分けるかの判断基準を整理します。

判断の軸として、次の2点を意識するとよいです。

1つ目は、「この処理は0回でも矛盾しないか?」という問いです。

0回でも問題ないならwhile文が自然であり、0回だとプログラムの意味が崩れるならdo-while文が適しています。

2つ目は、「読み手にとってわかりやすいか?」という視点です。

同じ動作をするコードでも、前判定で書いた方が直感的に理解しやすい場面と、後判定で書いた方が自然な場面があります。

とくにチーム開発では、他人が読んだときの分かりやすさも考慮することが大切です。

最終的には、「少なくとも1回実行する必要があるときにだけdo-whileを使う」というルールにしておくと、構造的に混乱しにくくなります。

まとめ

do-while文は、必ず1回は処理を実行する後判定ループとして、while文とは異なる役割を持ちます。

メニュー表示やユーザー入力のように「最低1回は実行したい処理」に向いており、うまく使えばコードを自然で読みやすくできます。

一方で、セミコロンの付け忘れ条件式のミスによる無限ループなど、初心者がハマりやすいポイントも多い構文です。

この記事で紹介した、初期化・更新・条件の3点チェックと、printfを使ったデバッグを意識しながら、while文との違いを踏まえて適切に使い分けていけば、do-while文を安心して活用できるようになります。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!