C言語基礎|do文とwhile文の違い

はじめに:do文とwhile文は「似てるけど性格が違う」ループ仲間

C言語の繰り返し処理で、まず混乱しやすいのが do文while文 です。
どっちもキーワードに while が出てくるので、ぱっと見で「あれ、これ do-while?普通の while?」ってなりがちなんですよね。

でも安心してください。コツさえ押さえれば、見分けも使い分けもスッキリします。

  • do文:まず1回やってから判定(後判定)
  • while文:まず判定してから実行(前判定)

そして読みやすさを上げる最大のコツは、do文の本体を必ず { } で囲むことです。

サンプル:正の整数だけ受け付けて、入力した数を逆順に表示する

「正の整数だけ受け付けて、入力した数を逆順に表示する」プログラムを例に解説をします。

  • do文:入力を正の整数に制限する。
  • while文:桁を取り出して逆順表示する。

プロジェクト名:chap4-11-1 ソースファイル名:chap4-11-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

// 正の整数だけ受け付けて、桁を逆順に表示
#include <stdio.h>

int main(void)
{
    int n;

    do {
        printf("正の整数を入力してください:");
        scanf("%d", &n);
        if (n <= 0)
            puts("0以下は受け付けません。もう一度入力してください。");
    } while (n <= 0);

    printf("逆順にすると:");

    while (n > 0) {
        printf("%d", n % 10);
        n /= 10;
    }

    puts(" です。");
    return 0;
}

実行例

正の整数を入力してください:-3
0以下は受け付けません。もう一度入力してください。
正の整数を入力してください:1963
逆順にすると:3691 です。

do文とwhile文の書式(見た目の違いをまず固定)

構文の違い

種類書式特徴
do文do 文 while (式);文を実行してから判定(後判定)
while文while (式) 文判定してから実行(前判定)

do文は最後に ;(セミコロン) が必要なのも、見分けポイントです。

プログラムの流れの違い(前判定 vs 後判定)

while文の基本フロー(日本語)

制御式を評価
    ↓
真(非0) → ループ本体を実行 → 制御式へ戻る
    ↓
偽(0)   → ループ終了

do文の基本フロー

ループ本体を実行(必ず1回)
    ↓
制御式を評価
    ↓
真(非0) → ループ本体へ戻る
    ↓
偽(0)   → ループ終了

ここが本質です。

  • while文:条件がダメなら 1回も実行されないことがある。
  • do文:条件がどうあれ 最低1回は実行される

見分けにくい問題:do文にもwhileが出る

do文とwhile文の両方に while が出てくるので、こういうコードは目が滑りやすいです。

例:見分けにくい書き方(イメージ)

x = 0;
do
    x++;
while (x < 5);

while (x >= 0)
    printf("%d ", --x);

「whileが2つある!」となった瞬間に、どっちがどっちか迷います。

読みやすさの鉄則:do文の本体は { } で囲む

do文は、ループ本体が1文でも 必ず複合文(ブロック)にすると読みやすくなります。

読みやすい形(do文の終わりが } で分かる)

x = 0;
do {
    x++;
} while (x < 5);

while (x >= 0)
    printf("%d ", --x);

見分けのコツ

その行の先頭何が分かる?
} while (式);do文の一部(do-whileの末尾)
while (式)while文の開始

} が見えたら do文の終端、これだけでも相当ラクになります。

サンプルの中での使い分け(doは入力チェック、whileは処理の繰り返し)

先ほどのサンプルでは、役割がきれいに分かれています。

do文:正の整数が入るまで入力を繰り返す

  • 目的:入力制限(入力チェック)
  • 理由:入力は最低1回は必要だから、do文と相性がいい

while文:n が 0 になるまで桁を取り出す

  • 目的:処理の繰り返し
  • 理由:n が最初から 0 なら繰り返し不要(前判定が自然)

while文のループ本体でやっていること(逆順表示の仕組み)

逆順表示は、毎回「一番下の桁」を取り出して捨てていく流れです。

ループ本体の2つの仕事

やること意味
最下位桁を表示n % 1010で割った余りが一番下の桁
右に1桁ずらすn /= 1010で割って下の桁を捨てる。

n = 1963 の変化

表示する n % 10n /= 10 後の n
13196
2619
391
410

n が 0 になったら while が終わるので、逆順が完成します。

ここで登場した命令の書式まとめ

do文

書式何をする?
do 文 while (式);文を実行してから式を評価し、真の間繰り返す。

while文

書式何をする?
while (式) 文式を評価して、真の間だけ文を繰り返す。

複合代入(ついでに復習)

書式何をする?
a /= ba を b で割って a に代入する。

演習問題

指定どおり、類似問題を3つ作ります(0以下なら何もしない系/繰り返し表示系/桁数系)。

演習4-7:正の整数の個数だけ A と B を交互に表示

正の整数 n を読み込み、n 個の文字を A と B で交互に表示せよ。
ただし、0 以下の整数が入力された場合は何も表示しない。

(例)
正の整数:7
ABABABA

解答例

#include <stdio.h>

int main(void)
{
    int n;

    printf("正の整数:");
    scanf("%d", &n);

    int i = 0;
    while (i < n) {
        putchar((i % 2 == 0) ? 'A' : 'B');
        i++;
    }
    if (n > 0) putchar('\n');

    return 0;
}

演習4-8:入力した個数だけ @ を縦に表示

正の整数 n を読み込み、@ を n 行にわたって縦に表示せよ。
ただし、0 以下の整数が入力された場合は何も表示しない。

(例)
正の整数:3
@
@
@

解答例

#include <stdio.h>

int main(void)
{
    int n;

    printf("正の整数:");
    scanf("%d", &n);

    while (n-- > 0) {
        putchar('@');
        putchar('\n');
    }

    return 0;
}

演習4-9:正の整数を読み込み、末尾の0の個数を表示

正の整数 n を読み込み、末尾に連続して付いている 0 の個数を表示せよ。
(例:12000 なら末尾の0は3個)
※ヒント:10で割り切れる間だけ繰り返す。

(例)
正の整数を入力してください:12000
末尾の0は3個です。

解答例

#include <stdio.h>

int main(void)
{
    int n;
    int cnt = 0;

    printf("正の整数を入力してください:");
    scanf("%d", &n);

    if (n <= 0) {
        puts("正の整数ではありません。");
        return 0;
    }

    while (n % 10 == 0) {
        cnt++;
        n /= 10;
    }

    printf("末尾の0は%d個です。\n", cnt);
    return 0;
}

まとめ:迷ったら「最低1回必要か?」で選ぶとブレない

  • 入力チェックみたいに、まず1回は実行したい → do文が自然
  • 条件に合うときだけ処理したい → while文が自然
  • 読みやすさは、do文の本体を { } にするだけで一気に上がる。
  • do文にも while が出るので、終端の } while (式); を目印にする。