C言語の基本|whileとforでのcontinue文の違い

同じcontinueでも、次に進む場所は同じではない。whileとforの更新タイミングを理解して、回数を正しく制御しよう。

continue文は、現在の回に残っている処理を飛ばし、次の繰り返しへ進むための制御文です。

while文でもfor文でも使用できますが、continue文の実行後に進む場所には大切な違いがあります。

  • while文では継続条件式へ戻る
  • for文では再設定式を実行してから継続条件式へ進む

この違いを理解していないと、カウンタ変数が予定どおりに増えなかったり、無限ループになったりすることがあります。

特に大切なのが、何を回数として数えるかです。

  • 正しい入力を5件集めたい
  • 入力自体を5回だけ行いたい

この2つは似ていますが、無効な入力があったときの扱いが異なります。正しい入力数が基準ならwhile文、入力回数が基準ならfor文が自然です。

ここではcontinue文の基本を確認したうえで、while文とfor文の処理の流れ、更新位置の注意点、使い分け方を詳しく見ていきます。

continue文の基本動作

continue文が実行されると、その回で残っているループ本体の処理が飛ばされます。ただし、break文とは違い、ループ自体は終了しません。

制御文実行後の動き
breakループ全体を終了する
continue現在の回の残りを飛ばし、次の繰り返しへ進む

基本的な書き方は次のとおりです。

繰り返し処理 {
    処理1;

    if (スキップ条件) {
        continue;
    }

    処理2;
}

スキップ条件が真なら、処理2は実行されません。条件が偽ならcontinue文を通らず、そのまま処理2へ進みます。

図1:whileとforで異なるcontinue後の進み先

この図から分かること

while文とfor文のどちらでも、continue文より後ろにあるループ本体の処理は飛ばされます。

違うのは、その後の移動先です。

while文では、そのまま継続条件式の判定へ戻ります。カウンタ変数の更新をループ本体に書いている場合、その更新もcontinue文によって飛ばされる可能性があります。

for文では、continue文の後に再設定式が実行されます。再設定式にcount++が書かれていれば、continue文を実行した回でもcountは増えます。

continue後の流れを表で整理する

while文とfor文の違いは、次の表で整理できます。

比較項目while文for文
continue後の移動先継続条件式再設定式
カウンタの更新場所ループ本体に書くことが多いfor文の再設定式に書ける
continueで更新が飛ぶ可能性ある再設定式なら飛ばされない
無効入力を回数に含めない処理書きやすい再設定式の回数は進む
入力回数を固定する処理書けるが管理が分散する書きやすい
得意な考え方条件を満たすまで続ける決めた回数だけ実行する

continue文そのものの意味は変わりません。違いを生むのは、各ループが更新処理をどこに持っているかです。

while文でcontinue文を使ったときの流れ

while文の基本形は次のとおりです。

初期化;

while (継続条件式) {
    処理;

    if (スキップ条件) {
        continue;
    }

    残りの処理;
    更新処理;
}

continue文が実行されると、残りの処理と更新処理が飛ばされ、継続条件式へ戻ります。

ただし、更新処理をcontinue文より前に置いている場合は、その更新が済んでから条件判定へ戻ります。

つまり、while文では更新処理の位置によって動作が変わります。

正しい測定値を5件集めるwhile文

ここでは、1以上の消費電力量を5件集めます。0以下の値は無効とし、正しい値が5件集まるまで入力を続けます。

有効な消費電力量を5件集めるプログラム

ファイル名:9_14_1.c

#include <stdio.h>

int main(void)
{
    int power;
    int total = 0;
    int valid_count = 0;

    while (valid_count < 5) {
        printf("消費電力量を入力してください > ");
        scanf("%d", &power);

        /* 0以下は無効なので、集計せずに次の入力へ進む */
        if (power <= 0) {
            printf("入力エラー:1以上の値を入力してください。\n");
            continue;
        }

        total += power;
        valid_count++;
    }

    printf("有効な測定値の合計は%dです。\n", total);

    return 0;
}
実行結果の例
消費電力量を入力してください > 120
消費電力量を入力してください > 150
消費電力量を入力してください > -10
入力エラー:1以上の値を入力してください。
消費電力量を入力してください > 90
消費電力量を入力してください > 130
消費電力量を入力してください > 110
有効な測定値の合計は600です。

while文では無効入力で回数が増えない

このプログラムでは、valid_countが有効な測定値の件数を表します。

while (valid_count < 5) {

0以下の値が入力されるとcontinue文が実行されます。

if (power <= 0) {
    printf("入力エラー:1以上の値を入力してください。\n");
    continue;
}

continue文より後ろにある次の処理は実行されません。

total += power;
valid_count++;

そのため、無効な値は合計に加えられず、valid_countも増えません。もう一度while文の継続条件式へ戻り、新しい入力を受け付けます。

実行例では6回入力していますが、有効な値は次の5件です。

入力順入力値判定valid_count
1回目120有効1
2回目150有効2
3回目-10無効2
4回目90有効3
5回目130有効4
6回目110有効5

-10が入力された回では、valid_countが2のままです。そのため、正しい値が5件集まるまで入力が続きます。

for文でcontinue文を使ったときの流れ

for文の基本形は次のとおりです。

for (初期設定式; 継続条件式; 再設定式) {
    処理;

    if (スキップ条件) {
        continue;
    }

    残りの処理;
}

continue文が実行されると、ループ本体の残りは飛ばされます。その後、for文の再設定式が実行されます。

for (int count = 1; count <= 5; count++)

この形なら、continue文が実行されてもcount++は行われます。そのため、無効な値が入力された回も、5回のうちの1回として数えられます。

入力自体を5回に固定するfor文

次のプログラムも消費電力量を入力します。ただし、こちらは有効な値を5件集めるのではなく、入力を5回だけ受け付けます。

5回の入力から有効な消費電力量だけを合計するプログラム

ファイル名:9_14_2.c

#include <stdio.h>

int main(void)
{
    int power;
    int total = 0;
    int valid_count = 0;

    for (int attempt = 1; attempt <= 5; attempt++) {
        printf("%d回目の消費電力量を入力してください > ", attempt);
        scanf("%d", &power);

        /* 0以下は合計せず、次の入力回へ進む */
        if (power <= 0) {
            printf("入力エラー:この回は集計しません。\n");
            continue;
        }

        total += power;
        valid_count++;
    }

    printf("有効な測定値は%d件です。\n", valid_count);
    printf("有効な測定値の合計は%dです。\n", total);

    return 0;
}
実行結果の例
1回目の消費電力量を入力してください > 120
2回目の消費電力量を入力してください > 0
入力エラー:この回は集計しません。
3回目の消費電力量を入力してください > 150
4回目の消費電力量を入力してください > 90
5回目の消費電力量を入力してください > 110
有効な測定値は4件です。
有効な測定値の合計は470です。

for文では無効入力でも入力回数が進む

2回目に0が入力されると、continue文が実行されます。そのため、totalへの加算とvalid_count++は飛ばされます。

ただし、for文の再設定式であるattempt++は実行されます。

for (int attempt = 1; attempt <= 5; attempt++)

そのため、0が入力された回も2回目として消費され、次は3回目の入力へ進みます。

入力回入力値集計次のattempt
1回目120加算する2
2回目0加算しない3
3回目150加算する4
4回目90加算する5
5回目110加算する6

attemptが6になるとattempt <= 5が偽になり、for文が終了します。

図2:無効入力をwhileとforで処理したときの違い

この図から分かること

while文では、カウンタ変数をcontinue文より後ろで更新することで、無効入力を成功件数に含めない処理を作れます。

for文では、continue文が実行されても再設定式へ進みます。そのため、無効入力でも入力回数は進みます。

どちらが正しいということではなく、数えたい対象が違います。

  • 有効なデータを必要件数だけ集めるならwhile文
  • 有効か無効かに関係なく入力回数を固定するならfor文

ループを書く前に、入力回数と成功回数のどちらを基準にするか決めておくと、適切な構文を選びやすくなります。

while文で更新を飛ばすと無限ループになることがある

while文でcontinue文を使うときは、継続条件に関係する変数の更新位置に注意が必要です。

次のコードには問題があります。

int i = 1;

while (i <= 5) {
    if (i == 3) {
        continue;
    }

    printf("%d\n", i);
    i++;
}

iが1と2の間は、printfとi++が実行されます。しかし、iが3になるとcontinue文が実行されます。

continue文より後ろにあるi++は飛ばされるため、iは3のままです。継続条件i <= 5は常に真になり、i == 3も毎回真になります。

その結果、iが3の状態で繰り返し続ける無限ループになります。

更新をcontinue文より前に置く

各回で必ずiを増やしたい場合は、continue文より前で更新します。

int i = 1;

while (i <= 5) {
    int current = i;
    i++;

    if (current == 3) {
        continue;
    }

    printf("%d\n", current);
}

このコードでは、currentに現在の値を保存した後でiを増やしています。currentが3なら表示は飛ばされますが、iはすでに4になっています。

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

1
2
4
5

continue文によって3の表示だけが飛ばされ、ループは正常に終了します。

更新を前に移動するときは、更新後の値を処理に使うのか、更新前の値を使うのかも確認しましょう。

for文では再設定式が実行される

同じ処理をfor文で書くと、更新位置が分かりやすくなります。

for (int i = 1; i <= 5; i++) {
    if (i == 3) {
        continue;
    }

    printf("%d\n", i);
}

iが3のときはprintfが飛ばされます。しかし、その後は再設定式i++へ進むため、iは4になります。

for文では、初期設定、継続条件、更新が1行にまとまっています。回数や範囲が決まったループでcontinue文を使う場合は、更新が行われることを確認しやすい書き方です。

4回成功するまで割り算を続ける

ここでは、2つの整数を入力し、商と余りを求めます。割る数が0なら計算できないため、その回をcontinue文で飛ばします。

入力を4回行うのではなく、割り算に4回成功するまで続けることが条件です。

4回の割り算が成功するまで入力を続けるプログラム

ファイル名:9_14_3.c

#include <stdio.h>

int main(void)
{
    int dividend;
    int divisor;
    int success = 0;

    while (success < 4) {
        printf("割られる数と割る数を入力してください > ");
        scanf("%d %d", ÷nd, &divisor);

        /* 0では割れないので、この回の計算を行わない */
        if (divisor == 0) {
            printf("エラー:0で割ることはできません。\n");
            continue;
        }

        printf("商:%d 余り:%d\n",
               dividend / divisor, dividend % divisor);

        success++;
    }

    printf("4回の計算が完了しました。\n");

    return 0;
}
実行結果の例
割られる数と割る数を入力してください > 22 5
商:4 余り:2
割られる数と割る数を入力してください > 8 0
エラー:0で割ることはできません。
割られる数と割る数を入力してください > 19 3
商:6 余り:1
割られる数と割る数を入力してください > 40 8
商:5 余り:0
割られる数と割る数を入力してください > 17 4
商:4 余り:1
4回の計算が完了しました。

successが増える条件を確認する

successは、入力した回数ではなく、割り算に成功した回数を表します。

int success = 0;

while (success < 4) {

divisorが0ならcontinue文が実行されます。

if (divisor == 0) {
    printf("エラー:0で割ることはできません。\n");
    continue;
}

この場合、割り算とsuccess++はどちらも実行されません。successは増えないため、4回の成功には含まれません。

divisorが0以外なら、商と余りを表示した後でsuccessを1増やします。

success++;

このように、成功したときだけカウンタを更新したい処理では、while文とcontinue文の組み合わせが便利です。

3回の入力を必ず行うfor文

次のプログラムでは、現在庫と出庫予定数を3回入力します。

現在庫が出庫予定数以上なら、出庫後の在庫を計算します。現在庫が足りない場合は、計算をcontinue文で飛ばします。

3回の在庫確認から出庫可能な場合だけ残数を表示するプログラム

ファイル名:9_14_4.c

#include <stdio.h>

int main(void)
{
    int stock;
    int shipment;
    int completed = 0;

    for (int attempt = 1; attempt <= 3; attempt++) {
        printf("%d回目の現在庫と出庫予定数を入力してください > ",
               attempt);
        scanf("%d %d", &stock, &shipment);

        if (stock < shipment) {
            printf("在庫が不足しているため出庫できません。\n");
            continue;
        }

        printf("出庫後の在庫:%d\n", stock - shipment);
        completed++;
    }

    printf("出庫可能だった回数:%d\n", completed);

    return 0;
}
実行結果の例
1回目の現在庫と出庫予定数を入力してください > 18 7
出庫後の在庫:11
2回目の現在庫と出庫予定数を入力してください > 5 12
在庫が不足しているため出庫できません。
3回目の現在庫と出庫予定数を入力してください > 20 8
出庫後の在庫:12
出庫可能だった回数:2

このプログラムは、出庫が成功するまで繰り返すのではありません。入力を3回行うことが条件です。

2回目ではcontinue文が実行されますが、for文の再設定式によってattemptは3になります。そのため、3回目の入力へ進みます。

入力回数は3回で固定され、出庫後の在庫を表示した回数だけcompletedで数えています。

while文とfor文を組み合わせる

多重ループでは、外側と内側で役割に合ったループを選べます。

たとえば、次の処理を考えてみましょう。

  • 外側は計算に2回成功するまで続ける
  • 割る数が0ならcontinue文で再入力する
  • 内側は小数点以下を最大20桁まで計算する
  • 途中で割り切れたらbreak文で内側だけを終了する

この場合、外側は成功回数が条件なのでwhile文が向いています。内側は最大20桁という回数が決まっているためfor文が向いています。

図3:外側whileと内側forで異なる制御文を使う

この図から分かること

多重ループでは、continue文とbreak文がどのループに属しているかを確認する必要があります。

外側のwhile文にあるcontinue文は、外側while文の次の繰り返しへ進みます。入力からやり直すため、内側のfor文には入りません。

内側のfor文にあるbreak文は、小数部分の計算だけを終了します。外側のwhile文まで終了するわけではありません。

制御文の役割は次のとおりです。

  • 外側whileは成功回数を管理する
  • 外側のcontinueは無効な入力を飛ばす
  • 内側forは小数点以下の桁数を管理する
  • 内側のbreakは割り切れた時点で小数計算を終える

小数点以下を最大20桁まで計算する

正の整数を2つ入力し、割り算の結果を表示します。計算に2回成功するまで入力を続けます。

割る数が0ならcontinue文で再入力し、小数部分が途中で割り切れたらbreak文で内側のfor文を終了します。

2回成功するまで小数の割り算を続けるプログラム

ファイル名:9_14_5.c

#include <stdio.h>

int main(void)
{
    int dividend;
    int divisor;
    int success = 0;

    while (success < 2) {
        int integer_part;
        int remainder;

        printf("正の整数を2つ入力してください > ");
        scanf("%d %d", ÷nd, &divisor);

        /* 0では割れないので、成功回数を増やさず再入力する */
        if (divisor == 0) {
            printf("エラー:0で割ることはできません。\n");
            continue;
        }

        integer_part = dividend / divisor;
        remainder = dividend % divisor;

        printf("%d / %d = %d", dividend, divisor, integer_part);

        if (remainder != 0) {
            printf(".");

            for (int digit = 0; digit < 20; digit++) {
                remainder *= 10;
                printf("%d", remainder / divisor);
                remainder %= divisor;

                /* 余りが0なら、それ以上の小数計算は不要 */
                if (remainder == 0) {
                    break;
                }
            }
        }

        printf("\n");
        success++;
    }

    return 0;
}
実行結果の例
正の整数を2つ入力してください > 9 4
9 / 4 = 2.25
正の整数を2つ入力してください > 8 0
エラー:0で割ることはできません。
正の整数を2つ入力してください > 10 6
10 / 6 = 1.66666666666666666666

外側のcontinue文が行うこと

divisorが0の場合は、次のcontinue文が実行されます。

if (divisor == 0) {
    printf("エラー:0で割ることはできません。\n");
    continue;
}

このcontinue文は、外側のwhile文に属しています。そのため、次の処理が飛ばされます。

  • 整数部分の計算
  • 余りの計算
  • 小数部分の表示
  • success++

successは増えないため、計算成功には含まれません。外側のwhile文の継続条件へ戻り、再び入力を受け付けます。

内側のbreak文が行うこと

小数部分を計算するfor文では、余りが0になったかを確認します。

if (remainder == 0) {
    break;
}

余りが0になれば、割り算は途中で割り切れています。それ以降の小数部分を計算する必要はありません。

このbreak文が終了するのは、digitを使っている内側のfor文だけです。外側のwhile文は終了しません。

9を4で割る場合は、次のように余りが変化します。

計算段階表示する数字新しい余り
整数部分21
小数第1位22
小数第2位50

小数第2位で余りが0になるため、内側のbreak文が実行され、2.25まで表示して小数計算を終えます。

10を6で割る場合は余りが0にならないため、内側のfor文が最大20回まで実行されます。

何を回数として数えるかで選ぶ

while文とfor文のどちらを使うか迷ったときは、繰り返しの基準を確認しましょう。

実現したい処理向いているループ
有効な入力を5件集めるwhile文
計算に4回成功するまで続けるwhile文
条件を満たすまで入力するwhile文
入力を5回だけ行うfor文
配列の全要素を処理するfor文
最大20桁まで計算するfor文

while文は条件達成まで続ける処理に向いています。continue文によってカウンタの更新を飛ばせば、無効な回を成功回数に含めない設計ができます。

for文は回数や範囲が明確な処理に向いています。continue文が実行されても再設定式を通るため、入力回数や要素番号は進みます。

continue文で何が飛ばされるか確認する

continue文を読むときは、次の順番で処理を追うと分かりやすくなります。

  1. continue文を直接囲んでいるループを確認する
  2. continue文より後ろにある処理を確認する
  3. カウンタの更新がどこにあるか確認する
  4. continue文の後に移動する位置を確認する
  5. 次の継続条件がいつ偽になるか確認する

特にwhile文では、継続条件に使う変数が変化するかを確認しましょう。

カウンタ変数の更新がcontinue文より後ろにあり、スキップ条件が何度も真になる場合は、カウンタが進まない可能性があります。それが意図した動作なのか、無限ループにつながるミスなのかを見分けることが大切です。

読みやすいcontinue文にするためのポイント

continue文を使うときは、スキップする理由と繰り返しの基準を分かりやすく表しましょう。

  • while文では更新処理の位置を確認する
  • for文では再設定式が実行されることを意識する
  • 入力回数と成功回数を区別する
  • continue文より後ろで何が飛ばされるか確認する
  • スキップ条件をif文にまとめる
  • カウンタ変数には役割が分かる名前を付ける
  • 多重ループではcontinue文が属するループを確認する
  • ループの終了条件がいつか偽になることを確認する

同じcontinue文でも、while文では継続条件式へ戻り、for文では再設定式へ進みます。この移動先の違いを意識すると、無効な回を数えるのか、成功した回だけを数えるのかを正しく設計できるようになります。