ループ処理を書いていると、条件に応じて途中で処理を止めたり、その周回だけ飛ばしたくなる場面が必ず出てきます。
C言語ではbreak
とcontinue
という2つのキーワードでこれを実現します。
本記事では、for文とwhile文における挙動の違いと実行フローを、サンプルコードと実行結果を交えて丁寧に解説し、読みやすさを保つ使い分けの指針まで押さえます。
C言語のbreakとcontinueの基本
breakの役割(ループを終了)
break
は、今いる最も内側のループ全体を即座に終了します。
以降のループ周回は行われず、ループ直後の文に制御が移ります。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
printf("i=%dでbreakします\n", i); // 5に到達したらループを終了
break;
}
printf("i=%d\n", i); // 1,2,3,4まで出力される
}
printf("ループ後の処理\n");
return 0;
}
i=1
i=2
i=3
i=4
i=5でbreakします
ループ後の処理
ループ本体の残りや、それ以降の周回は実行されません。
continueの役割(周回をスキップ)
continue
は、その周回の残りの処理だけをスキップし、次の周回へ進みます。
ループ自体は継続します。
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
// 偶数のときはこの周回の残りを飛ばして次へ
continue;
}
printf("%d ", i); // 奇数のみ出力
}
printf("\n");
return 0;
}
1 3 5 7 9
実行フローの違いと挙動
breakはループからの脱出、continueはループ継続という根本の違いに加え、for
とwhile
での「次にどこへ戻るか」が異なります。
for
でcontinue
が発生すると、更新式(ヘッダの3つ目)が実行されてから条件判定に戻ります。for
でbreak
が発生すると、更新式は実行されず、ループ直後へ移ります。while
では更新式が別に書かれるため、continue
を使う際はカウンタの更新忘れで無限ループを起こしやすい点に注意します。
下表に要点をまとめます。
振る舞い | ループ本体の残り | 次に実行される位置 | forの更新式 | 脱出の範囲 |
---|---|---|---|---|
break | 実行しない | ループ直後 | 実行されない | 最も内側の1つのループ |
continue | 実行しない | 次周回の先頭 | 実行される(forのみ) | 脱出しない |
特に「forの更新式が実行されるかどうか」は混乱しやすいため、次章で具体的に確かめます。
for文でのbreak/continueの挙動
break発生時のfor文の流れ
break
では更新式が実行されないことを、変数の値で確認します。
#include <stdio.h>
int main(void) {
int i; // ループ外で宣言して後で値を観察する
for (i = 0; i < 5; i++) {
printf("本体: i=%d\n", i);
if (i == 2) {
printf("i==2でbreak\n");
break; // 更新式(i++)は実行されない
}
}
printf("ループ直後: i=%d\n", i); // 2のまま
return 0;
}
本体: i=0
本体: i=1
本体: i=2
i==2でbreak
ループ直後: i=2
breakでは「更新式がスキップされる」ため、iは2のままです。
continue後に更新式は実行される
continue
では更新式が実行されるため、次の周回ではインクリメント済みの値に進みます。
#include <stdio.h>
int main(void) {
for (int i = 0; i < 5; i++) {
if (i == 2) {
printf("i==2でcontinue(この後に更新式のi++が動く)\n");
continue; // 更新式が動いて、次はi==3の周回へ
}
printf("印字: i=%d\n", i);
}
return 0;
}
印字: i=0
印字: i=1
i==2でcontinue(この後に更新式のi++が動く)
印字: i=3
印字: i=4
i==2の周回では印字を飛ばし、更新式によりi==3へ進んでいることがわかります。
多重forでのbreakの効き方
break
は「最も内側のループ」だけを終了します。
外側のループは続行します。
#include <stdio.h>
int main(void) {
for (int y = 1; y <= 2; y++) { // 外側
for (int x = 1; x <= 3; x++) { // 内側
if (x == 2) {
printf("(y=%d)x==2で内側だけbreak\n", y);
break; // 内側のforからだけ脱出
}
printf("y=%d x=%d\n", y, x);
}
printf("外側は継続中 y=%d\n", y);
}
return 0;
}
y=1 x=1
(y=1)x==2で内側だけbreak
外側は継続中 y=1
y=2 x=1
(y=2)x==2で内側だけbreak
外側は継続中 y=2
多重ループを一気に抜けたい場合、breakだけでは足りません。
後述の「多重ループをまとめて抜ける考え方」で扱います。
for(;;)の無限ループをbreakで抜ける
for(;;)
は条件なしの無限ループです。
終了条件を本体側で判定してbreak
で抜けます。
#include <stdio.h>
int main(void) {
int count = 0;
for (;;) { // 無限ループ
printf("処理中... count=%d\n", count);
if (count >= 3) {
printf("条件達成でbreak\n");
break; // ループ終了
}
count++; // 進捗を進める
}
printf("ループを抜けました\n");
return 0;
}
処理中... count=0
処理中... count=1
処理中... count=2
処理中... count=3
条件達成でbreak
ループを抜けました
while文でのbreak/continueの挙動
break発生時のwhile文の流れ
while
でもbreak
はループを終了します。
for
と同様に、以降の周回は行いません。
#include <stdio.h>
int main(void) {
int i = 0;
while (i < 5) {
printf("i=%d\n", i);
if (i == 3) {
printf("i==3でbreak\n");
break;
}
i++; // 更新は自分で書く
}
printf("ループ後 i=%d\n", i);
return 0;
}
i=0
i=1
i=2
i=3
i==3でbreak
ループ後 i=3
continue後は条件判定へ戻る
while
ではcontinue
すると、ただちにループ先頭へ戻って条件判定が行われます。
更新は自分で記述する必要があるため、更新を飛ばすと無限ループになります。
#include <stdio.h>
int main(void) {
int i = 0;
while (i < 5) {
if (i == 2) {
printf("i==2でcontinue(更新i++を先に行う)\n");
i++; // 先に更新してからcontinue
continue; // 以降の本体処理をスキップ
}
printf("処理: i=%d\n", i);
i++; // 通常の更新
}
return 0;
}
処理: i=0
処理: i=1
i==2でcontinue(更新i++を先に行う)
処理: i=3
処理: i=4
continueの前にカウンタ更新を行う配置が、安全な書き方です。
入力チェックでcontinueを使う例
ユーザー入力から正の整数だけを合計し、負や0は注意を出してスキップします。
continue
で「その周回の残り」を飛ばします。
#include <stdio.h>
int main(void) {
int sum = 0;
int n;
int count = 0;
printf("正の整数を5回入力してください(負や0は無視します)\n");
while (count < 5) {
printf("%d回目: ", count + 1);
if (scanf("%d", &n) != 1) {
// 入力失敗時はバッファを捨てる簡易対応(実務ではより厳密に)
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) { /* 破棄 */ }
printf("数値を入力してください\n");
continue; // カウントを進めず再入力
}
if (n <= 0) {
printf("正の整数ではありません。やり直してください\n");
continue; // 合計せず再入力
}
sum += n;
count++; // 有効入力のみ数える
}
printf("合計=%d\n", sum);
return 0;
}
正の整数を5回入力してください(負や0は無視します)
1回目: -2
正の整数ではありません。やり直してください
1回目: abc
数値を入力してください
1回目: 3
2回目: 5
3回目: 0
正の整数ではありません。やり直してください
3回目: 7
4回目: 10
5回目: 2
合計=27
無効入力の処理を短く切り上げて次の入力に進めるのがcontinue
の得意分野です。
使い分けと注意点(C言語)
使い分けの指針(読みやすさ)
「読んだ人が一度で意図を理解できるか」を基準に選びます。
条件に合致したらループ全体を終わらせたいならbreak
、処理対象外なのでその周回だけ飛ばしたいならcontinue
です。
ネストが深い場所に複雑なbreak/continueが点在すると流れが追いにくくなるため、条件分岐の構造自体を見直す選択肢も検討します。
多重ループをまとめて抜ける考え方
break
は1段分しか抜けません。
2段以上を抜けたいときの代表的アプローチは次のとおりです。
- フラグ変数で外側のループも抜ける
#include <stdio.h>
int main(void) {
int found = 0;
for (int y = 0; y < 3 && !found; y++) {
for (int x = 0; x < 3; x++) {
if (x == 1 && y == 2) {
printf("見つけたので二重ループを脱出\n");
found = 1; // フラグを立てる
break; // 内側を抜ける
}
printf("探索中 y=%d x=%d\n", y, x);
}
// foundが1なら外側の継続条件で抜ける
}
printf("終了 found=%d\n", found);
return 0;
}
探索中 y=0 x=0
探索中 y=0 x=1
探索中 y=0 x=2
探索中 y=1 x=0
探索中 y=1 x=1
探索中 y=1 x=2
探索中 y=2 x=0
見つけたので二重ループを脱出
終了 found=1
- ラベルとgotoで一気に脱出(用途限定で)
#include <stdio.h>
int main(void) {
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
if (x == 2 && y == 1) {
printf("ラベルへジャンプして全体を脱出\n");
goto OUT; // 多重ループを瞬時に抜ける
}
printf("走査 y=%d x=%d\n", y, x);
}
}
OUT:
printf("OUTラベル後\n");
return 0;
}
走査 y=0 x=0
走査 y=0 x=1
走査 y=0 x=2
走査 y=1 x=0
走査 y=1 x=1
ラベルへジャンプして全体を脱出
OUTラベル後
gotoは可読性を損ねやすいため、例外処理的な早期脱出に限定し、可能なら関数分割やフラグ方式を優先します。
breakとreturnの違い
return
は関数からの復帰であり、break
のように「ループだけ」を抜けるわけではありません。
#include <stdio.h>
void demo_break(void) {
for (int i = 0; i < 3; i++) {
if (i == 1) {
printf("breakでループだけ終了\n");
break; // 関数は続行する
}
printf("i=%d\n", i);
}
printf("demo_breakの後続処理\n");
}
void demo_return(void) {
for (int i = 0; i < 3; i++) {
if (i == 1) {
printf("returnで関数を終了\n");
return; // 関数自体を抜ける
}
printf("i=%d\n", i);
}
printf("この行は実行されません\n");
}
int main(void) {
demo_break();
demo_return();
printf("mainの終わり\n");
return 0;
}
i=0
breakでループだけ終了
demo_breakの後続処理
i=0
returnで関数を終了
mainの終わり
breakは制御の射程が「ループまで」、returnは「関数まで」と覚えると混同しません。
乱用を避けるコツ
- 意図が単純なときに使うと読みやすく、複雑な分岐や多段ネストの中で多用すると読みにくくなります。条件を見直し、早期リターンや関数分割でネストを浅くする方が明確な場合があります。
while
でcontinue
を使う際は更新忘れの無限ループに注意し、continue前に更新するパターンを徹底します。for
ではcontinue
後に更新式が走る点を前提に、副作用のある更新式は簡潔に保つと誤解が減ります。
まとめ
breakはループからの脱出、continueは周回だけのスキップであり、for
ではcontinue
後に更新式が実行され、break
時は実行されないという違いが肝心です。
whileでは更新を自前で書くため、特にcontinue
の位置に注意が必要です。
多重ループの脱出にはフラグや関数分割、場合によりgoto
も選択肢ですが、可読性を最優先してください。
今回のポイントを押さえれば、意図どおりにループを制御でき、シンプルで保守しやすいコードに近づけます。