閉じる

【C言語】breakとcontinueの違いと使いどころ|間違えやすいケースを徹底解説

C言語を学び始めると、ループやswitch文で必ず登場するのがbreakcontinueです。

同じような場所で使われるため混同しやすい一方で、動作はまったく異なります。

本記事では、両者の違いと使いどころを丁寧に整理しながら、典型的な間違いパターンまで詳しく解説していきます。

C言語のbreakとcontinueとは

breakとcontinueの基本的な意味

breakcontinueは、どちらも「通常の流れを途中で変える」ためのキーワードです。

しかし、どこまで処理を止めるかが大きく異なります。

breakは「今いるループやswitch文そのものを途中で終了する命令」です。

for文やwhile文、do-while文、switch文の内部で利用でき、実行されるとそのブロックから即座に抜け出します

一方、continueは「今の1回分のループ処理だけを打ち切り、次の繰り返しに進む命令」です。

for文やwhile文などのループ内でのみ利用でき、switch文では使えません。

continueが実行されると、残りの処理をスキップして、次のループ開始処理へ移ります

ここで大切なのは、breakは「ループ/switch自体を終わらせる」、continueは「1回分の途中を飛ばす」という違いです。

ループ(for/while)でのbreakとcontinueの動き

ループの中でbreakとcontinueがどのように動作するのか、for文を例に確認します。

具体的なサンプルコードを見てみます。

C言語
#include <stdio.h>

int main(void) {
    // 1〜10の数字を順に表示します
    // 5になったら break でループを終了します
    for (int i = 1; i <= 10; i++) {
        if (i == 5) {
            printf("i = %d のときに break します\n", i);
            break;  // ここで for ループ自体が終了します
        }
        printf("i = %d\n", i);
    }

    printf("for ループを抜けました\n");

    // もう一度 1〜10 を回しますが、
    // 今度は 5 のときだけ continue して表示をスキップします
    for (int i = 1; i <= 10; i++) {
        if (i == 5) {
            printf("i = %d のときに continue します\n", i);
            continue;  // 残りの処理を飛ばして次の i へ
        }
        printf("i = %d\n", i);
    }

    return 0;
}
実行結果
i = 1
i = 2
i = 3
i = 4
i = 5 のときに break します
for ループを抜けました
i = 1
i = 2
i = 3
i = 4
i = 5 のときに continue します
i = 6
i = 7
i = 8
i = 9
i = 10

この例から分かるように、breakはループ全体を強制終了しますが、continueはその周だけをスキップしてループを継続します。

switch文におけるbreakの役割

switch文では、breakはほぼ必須のキーワードです。

breakを書き忘れると、意図せず次のcaseに処理が「落ちて」進んでしまうので注意が必要です。

簡単なswitch文の例を確認します。

C言語
#include <stdio.h>

int main(void) {
    int menu = 2;

    printf("menu = %d のときの switch 文の例\n", menu);

    switch (menu) {
        case 1:
            printf("メニュー1が選択されました\n");
            break;  // ここで switch 文を抜けます

        case 2:
            printf("メニュー2が選択されました\n");
            break;  // ここで switch 文を抜けます

        case 3:
            printf("メニュー3が選択されました\n");
            break;

        default:
            printf("不正なメニュー番号です\n");
            break;
    }

    printf("switch 文を抜けました\n");
    return 0;
}
実行結果
menu = 2 のときの switch 文の例
メニュー2が選択されました
switch 文を抜けました

このように、switch文におけるbreakは「そのcaseの処理を終えたらswitch全体から抜ける」ためのものです。

continueはswitch文の中では使えないことも、後ほど詳しく説明します。

breakの使いどころと注意点

無限ループからの脱出に使うbreakの書き方

C言語では、無限ループとbreakを組み合わせて柔軟な繰り返し処理を書くことがよくあります。

典型的なパターンはwhile (1)for (;;)とbreakの組み合わせです。

サンプルとして、ユーザーからの入力を受け取り、特定の文字で終了するプログラムを示します。

C言語
#include <stdio.h>

int main(void) {
    char c;

    printf("文字を入力してください。(q で終了)\n");

    // while(1) を使った無限ループ
    while (1) {
        printf("入力: ");
        if (scanf(" %c", &c) != 1) {
            // 入力エラー時もループ終了
            printf("入力エラーのため終了します。\n");
            break;
        }

        if (c == 'q') {
            printf("'q' が入力されたのでループを終了します。\n");
            break;  // 無限ループから抜ける
        }

        printf("あなたが入力した文字: %c\n", c);
    }

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

このように、終了条件をif+breakで書くと、複雑な条件でも柔軟に対応できます。

switch文でbreakを入れ忘れたときの挙動

switch文でbreakを入れ忘れると、次のcaseの処理までそのまま実行されるという挙動(cst-code>fall throughと呼ばれます)になります。

これを知らないとバグの原因になります。

例として、breakを入れ忘れた場合の挙動を見てみます。

C言語
#include <stdio.h>

int main(void) {
    int rank = 2;

    printf("rank = %d のときの switch 文 (break なしの例)\n", rank);

    switch (rank) {
        case 1:
            printf("Gold\n");
            // break を忘れている
        case 2:
            printf("Silver\n");
            // break を忘れている
        case 3:
            printf("Bronze\n");
            // break を忘れている
        default:
            printf("Other\n");
    }

    return 0;
}
実行結果
rank = 2 のときの switch 文 (break なしの例)
Silver
Bronze
Other

rankが2にもかかわらず、Silver → Bronze → Otherとすべて表示されています。

これは、case 2に入ったあとbreakがないため、そのまま下のcase 3、defaultへと処理が進んでしまったからです。

逆に、意図的に複数のcaseをまとめて処理したい場合には、あえてbreakを書かないというテクニックも存在します。

C言語
// rank が 1 または 2 のときは「上位ランク」としたい例
switch (rank) {
    case 1:
    case 2:
        printf("上位ランクです\n");
        break;
    default:
        printf("その他のランクです\n");
        break;
}

このように、breakの有無によって挙動が大きく変わるので、意図しているかどうかを常に意識して書くことが重要です。

多重ループでのbreakの効き方

多重ループ(ネストされたforやwhile)では、breakは「今いる一番内側のループ」にしか効かないという点に注意する必要があります。

次の例で挙動を確認します。

C言語
#include <stdio.h>

int main(void) {
    // 2重ループの中で break を使う例
    for (int i = 1; i <= 3; i++) {          // 外側ループ
        for (int j = 1; j <= 5; j++) {      // 内側ループ
            if (j == 3) {
                printf("i = %d, j = %d で break\n", i, j);
                break;  // 内側ループだけを抜ける
            }
            printf("i = %d, j = %d\n", i, j);
        }
        printf("外側ループ i = %d が 1回終了\n", i);
    }

    return 0;
}
実行結果
i = 1, j = 1
i = 1, j = 2
i = 1, j = 3 で break
外側ループ i = 1 が 1回終了
i = 2, j = 1
i = 2, j = 2
i = 2, j = 3 で break
外側ループ i = 2 が 1回終了
i = 3, j = 1
i = 3, j = 2
i = 3, j = 3 で break
外側ループ i = 3 が 1回終了

このように、breakは常に「最も内側の1つのループ」だけから抜けるという動作になります。

外側のループごと完全に抜けたい場合は、後述するラベル付きbreak(goto)などの手法を検討します。

ifとbreakの組み合わせで処理を早期終了する

ループの中で「特定の条件を満たした時点で、これ以上処理を続ける意味がない」といった場面では、if文とbreakを組み合わせて早期終了することで、処理時間を短縮できます。

例えば、配列の中から特定の値を探す線形探索では、見つかった瞬間にループを終えるのが効率的です。

C言語
#include <stdio.h>

int main(void) {
    int data[] = {3, 8, 2, 7, 5};
    int size = sizeof(data) / sizeof(data[0]);
    int target = 7;
    int found_index = -1;

    // data 配列の中から target を探します
    for (int i = 0; i < size; i++) {
        if (data[i] == target) {
            found_index = i;
            // 見つかったのでこれ以上探す必要はありません
            break;
        }
    }

    if (found_index != -1) {
        printf("値 %d はインデックス %d で見つかりました。\n", target, found_index);
    } else {
        printf("値 %d は配列内に見つかりませんでした。\n", target);
    }

    return 0;
}

このような「条件を満たしたらbreak」パターンは、多くのアルゴリズムで使われる典型的な書き方です。

continueの使いどころと注意点

ループの一部処理をスキップするcontinueの使い方

continueは、ループ内の「残りの処理」を飛ばして、次の繰り返しへ進むために使います。

これにより、条件によって「この周はここから先はやらない」といった制御が簡単に書けます。

例として、1〜10のうち偶数だけ処理し、奇数はスキップするコードを示します。

C言語
#include <stdio.h>

int main(void) {
    printf("1〜10 のうち偶数だけ表示します。\n");

    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 1) {
            // i が奇数のときは、この周の残り処理をスキップ
            continue;
        }

        // ここに来るのは i が偶数のときだけ
        printf("偶数: %d\n", i);
    }

    return 0;
}
実行結果
1〜10 のうち偶数だけ表示します。
偶数: 2
偶数: 4
偶数: 6
偶数: 8
偶数: 10

このように、continueを使うと「特定の条件のときだけ、この先の処理を行う」構造がすっきり書けるようになります。

for文でのcontinueとインクリメント処理の順番

for文は初期化; 条件; インクリメントという3つの部分から成り立っています。

continueを使ったときに、インクリメント処理がいつ実行されるかは重要なポイントです。

for文の流れは次のようになります。

  1. 初期化
  2. 条件判定(偽ならループ終了)
  3. 本体を実行
  4. インクリメント処理
  5. 2に戻る

continueが本体の途中で実行されると、残りの本体はスキップされるが、インクリメント処理は必ず実行されます。

C言語
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 5; i++) {
        if (i == 2) {
            printf("i = %d で continue\n", i);
            continue;  // ここで本体の残りをスキップ
        }
        printf("本体の処理 i = %d\n", i);
    }
    return 0;
}
実行結果
本体の処理 i = 0
本体の処理 i = 1
i = 2 で continue
本体の処理 i = 3
本体の処理 i = 4

この例から分かるように、continueの後でもiはしっかりインクリメントされているため、ループが先へ進みます。

while文でcontinueを使うときの無限ループ注意点

while文でcontinueを使うときに起こりやすいのが、インクリメントをし忘れて無限ループになるというミスです。

for文とは違い、while文ではインクリメントを自分で書く必要があるためです。

誤った例を先に示します。

C言語
#include <stdio.h>

int main(void) {
    int i = 0;

    // このコードには問題があります
    while (i < 5) {
        if (i == 2) {
            printf("i = %d で continue (誤った例)\n", i);
            continue;  // i を増やさずに continue してしまう
        }

        printf("i = %d\n", i);
        i++;  // インクリメント
    }

    return 0;
}

このコードは、i が 2 になったときに無限ループになります。

なぜなら、iが2のときにcontinueしてしまうと、i++の行が実行されないため、iはずっと2のままになってしまうからです。

正しい書き方の一例は次のようになります。

C言語
#include <stdio.h>

int main(void) {
    int i = 0;

    while (i < 5) {
        if (i == 2) {
            printf("i = %d で continue (正しい例)\n", i);
            i++;       // 先にインクリメントしてから continue
            continue;
        }

        printf("i = %d\n", i);
        i++;  // インクリメント
    }

    return 0;
}
実行結果
i = 0
i = 1
i = 2 で continue (正しい例)
i = 3
i = 4

このように、while文でcontinueを使うときは、ループ変数の更新タイミングに特に注意が必要です。

continueと条件分岐(if)の書き方のコツ

continueを多用すると、「やらない条件」を先に書いてどんどんスキップするスタイルになります。

これをうまく使うと、ネストの浅い読みやすいコードを書けます。

例えば、複数条件を満たした要素だけを処理したいとき、次の2パターンを比べてみます。

ネストが深い例:

C言語
for (int i = 0; i < n; i++) {
    if (is_valid(a[i])) {
        if (a[i] > 0) {
            if (a[i] % 2 == 0) {
                // 条件をすべて満たしたときの処理
            }
        }
    }
}

continueを使ってガード節にした例:

C言語
for (int i = 0; i < n; i++) {
    if (!is_valid(a[i])) {
        continue;
    }
    if (a[i] <= 0) {
        continue;
    }
    if (a[i] % 2 != 0) {
        continue;
    }

    // ここに来た時点で、すべての条件を満たしている
    // 条件をすべて満たしたときの処理
}

後者の方が、「満たしていない場合は早めに抜ける」という流れがはっきりしていて読みやすいことが多いです。

breakとcontinueで間違えやすいケース

breakとcontinueの違いを取り違える典型例

初心者がよくやってしまうのが、「ここはループを抜けたい」のにcontinueを書いてしまう、またはその逆というミスです。

次のような例を考えます。

負の値が入力されたら入力処理をやめたい場合、本来はbreakを使うべきです。

C言語
#include <stdio.h>

int main(void) {
    int n;

    while (1) {
        printf("正の整数を入力してください。(負の値で終了)\n");
        scanf("%d", &n);

        if (n < 0) {
            // ここで continue と書いてしまうと…
            // continue;  // 間違った書き方
            break;        // 正しいのはこちら
        }

        printf("入力された値は %d です。\n", n);
    }

    printf("入力処理を終了しました。\n");
    return 0;
}

ここで間違えてcontinueを書いてしまうと、負の値を入力してもループが終わらず、延々と入力を求め続けることになります。

「ループ全体を終えたいのか」「この1回分だけスキップしたいのか」を常に意識することが重要です。

switchの中でcontinueを使えない理由

C言語では、switch文の中でcontinueを書くとコンパイルエラーになります。

continueは「ループの次の繰り返しへ進む」ためのキーワードであり、switch文自体はループではないからです。

誤ったコード例を示します。

C言語
#include <stdio.h>

int main(void) {
    int i = 1;

    switch (i) {
        case 1:
            printf("case 1\n");
            continue;  // コンパイルエラーになる
        default:
            printf("default\n");
            break;
    }

    return 0;
}

このコードは、「continue文の対象となる反復文が存在しません」といったエラーになります。

ただし、switchがループの中に書かれている場合、switchの中にあるcontinueは「そのループに対するcontinue」として解釈されます。

例えば次のようなコードは有効です。

C言語
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 3; i++) {
        int n = i % 2;

        switch (n) {
            case 0:
                printf("i = %d は偶数\n", i);
                break;  // switch を抜ける
            case 1:
                printf("i = %d は奇数なので、この周の残り処理をスキップ\n", i);
                continue;  // for ループの次の周へ
        }

        // n が 0 (偶数) のときだけ実行される処理
        printf("偶数のときだけ行う追加処理 i = %d\n", i);
    }

    return 0;
}
実行結果
i = 0 は偶数
偶数のときだけ行う追加処理 i = 0
i = 1 は奇数なので、この周の残り処理をスキップ
i = 2 は偶数
偶数のときだけ行う追加処理 i = 2

ここでは、continueはforループに対して効いている点がポイントです。

ラベル付きbreak(goto)と混同しやすいケース

C標準自体には「ラベル付きbreak」はありませんが、「外側のループまで一気に抜けたい」ときにgotoで似たような動作を実現することがあります。

このため、「breakでどこまで抜けられるのか」が混乱しやすくなります。

次のコードは、gotoで多重ループを一気に抜ける例です。

C言語
#include <stdio.h>

int main(void) {
    int found_i = -1, found_j = -1;

    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            if (i * j == 6) {
                found_i = i;
                found_j = j;
                // 多重ループ全体から抜けたいので goto を使用
                goto END_SEARCH;
            }
        }
    }

END_SEARCH:
    if (found_i != -1) {
        printf("i * j = 6 となる組み合わせ: i = %d, j = %d\n", found_i, found_j);
    } else {
        printf("条件を満たす組み合わせは見つかりませんでした。\n");
    }

    return 0;
}
実行結果
i * j = 6 となる組み合わせ: i = 2, j = 3

この例は分かりやすいものの、gotoは乱用するとコードが読みにくくなりやすいという欠点があります。

C++など他の言語にはラベル付きbreak構文を持つものもありますが、C言語標準には存在しないため、break自体は常に1段階だけ抜けると覚えておくと混乱しにくくなります。

ネストが深いループでのbreak/continueの読みづらさ対策

ループのネストが深くなると、どのbreakやcontinueがどのループに効いているのかが分かりづらくなってきます。

読みやすさのために、いくつかの工夫が有効です。

対策として、次のような方法があります。

1つ目は、コメントで「どのループに対するbreak/continueなのか」を明示する方法です。

C言語
for (int i = 0; i < 10; i++) {          // 外側ループ
    for (int j = 0; j < 10; j++) {      // 中間ループ
        for (int k = 0; k < 10; k++) {  // 内側ループ
            if (条件A) {
                // 内側ループを抜ける
                break;  // break inner-loop (k ループ)
            }
            if (条件B) {
                // 中間ループを抜けたい場合は工夫が必要
                // (フラグを立てて外側で break する、など)
            }
        }
    }
}

2つ目は、処理を関数に切り出すことで、1つの関数の中でのネストの深さを抑える方法です。

C言語
#include <stdbool.h>

bool process_inner_loop(int i) {
    for (int j = 0; j < 10; j++) {
        if (/* ある条件 */) {
            return true;  // 特別な状態を通知して「事実上の多重 break」
        }
    }
    return false;
}

int main(void) {
    for (int i = 0; i < 10; i++) {
        if (process_inner_loop(i)) {
            // 内側の処理から「やめたい」という合図が来たので外側も終了
            break;
        }
    }
    return 0;
}

このように、ネストが深くなるほど、break/continueを減らし、処理を分割して見通しを良くすることが大切です。

まとめ

breakとcontinueは、どちらも「通常の流れを変える」キーワードですが、breakはループやswitchそのものを終了し、continueはその周の残り処理だけをスキップする点が決定的に異なります。

特に、switch文でのbreak忘れや、while文+continueでのインクリメント忘れ、多重ループでの対象ループの勘違いなどは典型的な落とし穴です。

目的が「ループ全体を終わらせたいのか」「この1回分だけ飛ばしたいのか」を常に意識しながら書けば、breakとcontinueを安全かつ効果的に使いこなせるようになります。

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

URLをコピーしました!