【C言語】breakとcontinueについて解説(ループを抜け出す・ループをスキップする)

breakとcontinueの解説ページアイキャッチ

このページでは、C言語における breakcontinue について解説していきたいと思います。

これら2つは whilefor ループ処理において非常に便利な命令です。これらを使いこなすことで様々なループを簡潔に記述することができるようになります。

ただ、慣れないうちは breakcontinue を混同しがちですので、是非このページで breakcontinue の動きの違いや使い所の違いをしっかり理解していただければと思います。

break

では、まずは最初に break について解説していきます。

break に関しては switch 文で使用することもありますが、ここではループ内で使用する break に焦点を当てて解説を行います。

break:ループを抜け出す

break は “ループを抜け出す” 命令になります。

break を実行すると、下の図のようにループブロックの外側、つまり、ループの終了を示す }(閉じ括弧)の “外側に” 即座に処理が移ります。

breakの説明図

ループ処理が残っている場合でも、それらの処理を中断して即座にループ終了後の処理を実行することが可能です。

ループを抜け出す目的で break を使用する際には、whilefor のループの内側で braek を実行する必要があります。

また break は、”ある条件が成立したときにループを抜け出す目的” で利用するのが一般的です(常にループを抜け出すように breakしてしまうと、それはもはやループではないですよね…)。

なので、基本的に breakif 文と組み合わせて使用します。具体的には、下記のように if 文の条件式に “ループを抜け出す条件” を指定し、それが成立したときに break を実行してループを抜け出すように記述します。

ループを抜け出す条件の指定
while (ループを続ける条件) {
    if (ループを抜け出す条件) {
        break;
    }
}

スポンサーリンク

break の使い所

break の使い所の1つが “無限ループを終了させたい” ときです。

特定の条件を満たすまで無限ループで処理を待機したいような場合に、この break をよく使用します。

例えば下記は、ユーザーが正の整数を入力するまで無限にユーザーからの数値の入力を受け付けるループになります。

無限ループをbreakで抜け出す例
#include <stdio.h>

int main(void) {

    int x;

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

        if (x >= 0) {
            /* 正常な数値が入力されたらループ終了 */
            break;
        }
    }

    return 0;/* 変数宣言 */
int data = 0;

void calc(void) {

    data = data * 1.1;
}

void set(int num) {
    data = num;
}

int get(void) {
    return data;
}
}

また、データの探索などでも break はよく使います。

例えば、配列に “1つしか存在しない数値” をループ処理で配列から探索する場合を考えてみましょう!

この場合、探索したい数値が1度見つかれば、その後探索を続ける意味はありません。もうその数値は配列内に存在しないので、探索するだけ無駄な処理になってしまいます。

こんなときに break を利用すれば、その無駄な処理を行うことなくループを抜け出すことができます。

その後のループが不要な場合にbreakで抜け出す例
#include <stdio.h>

int main(void) {

    int a[100];
    int i;

    for (i = 0; i < 100; i++) {
        a[i] = i;
    }

    for (i = 0; i < 100; i++) {
        if (a[i] == 37) {
            /* もう探す必要がないのでループ終了 */
            printf("37が見つかりました\n");
            break;
        }
    }

    return 0;
}

break 利用時の注意点

break で抜け出すことができるのは、その break から見て “一番内側のループ” のみです。なので、例えば2重ループの内側のループで break を実行した場合は、内側のループからは抜け出すことはできますが、外側のループからは抜け出すことはできません。

breakでは外側のループから抜け出せない様子

内側のループで break すると外側のループも break されると勘違いすることが多いので注意してください。

例えば、上記で紹介した探索を2重ループの中で実行する例を考えてみましょう。先ほど同様に配列の中に “1つしか存在しない数値” を探索する場合として考えたいと思います。

2重ループが上手くbreakで抜け出せない例
#include <stdio.h>

int main(void) {

    int a[100][100];
    int x, y;

    for (y = 0; y < 100; y++) {
        for (x = 0; x < 100; x++) {
            a[y][x] = y * 100 + x;
        }
    }

    for (y = 0; y < 100; y++) {
        for (x = 0; x < 100; x++) {
            if (a[y][x] == 3749) {
                /* もう探す必要がないのでループ終了 */
                printf("3749が見つかりました\n");
                break;
            }
        }
        /* breakで処理が移動してくる位置 */
        printf("%d行目の探索完了!!!\n", y);
    }

    return 0;
}

この場合、見つけたいデータが探索できたあとは、その後の探索処理(ループ処理)は無駄な処理になってしまいます。ですが、内側のループ(x のループ)の中で break しただけでは、内側のループを抜け出すだけで、外側のループからは抜け出すことはできません。

ですので、外側のループでまた探索処理を再開してしまうので、また内側のループも実行されてしまい、無駄な探索処理が継続されることになってしまいます(配列の中に1つしか存在しない数値を探索しているので今後 break が実行されることもありません)。

こういった多重ループを break で抜け出すためには、内側のループで break が実行されたことを検知し、その際に外側のループでも break を実行するようにする必要があります。

例えば下記のように内側のループで break を実行する際に isFind を 1 にセットするようにし、外側のループでは isFind1 の時に break を実行するようにすれば、内側の break が実行された際に外側のループも break で抜け出すことができるようになります。

2重ループが上手くbreakで抜け出せない例
#include <stdio.h>

int main(void) {

    int a[100][100];
    int x, y;
    int isFind; /* 探索完了フラグを用意 */

    for (y = 0; y < 100; y++) {
        for (x = 0; x < 100; x++) {
            a[y][x] = y * 100 + x;
        }
    }

    /* 探索開始前にisFindを0に初期化 */
    isFind = 0;

    for (y = 0; y < 100; y++) {
        for (x = 0; x < 100; x++) {
            if (a[y][x] == 3749) {
                /* もう探す必要がないのでループ終了 */
                printf("3749が見つかりました\n");

                /* 探索完了時にisFindを1にセット */
                isFind = 1;
                break;
            }
        }

        if (isFind == 1) {
            /* isFindが1で探索完了しているのでループ終了 */
            break;
        }

        printf("%d行目の探索完了!!!\n", y);
    }

    return 0;
}

ただし、特に何重もループさせている場合は break で抜け出そうと思うとソースコードが冗長&複雑になってしまうため、goto を利用してループから抜け出すようにしてしまうのも1つの手だと思います。

また、何重にも重なっている if 文の中で break を実行するようなこともあります。このような場合でも、break で抜け出すのは、その break から見て “一番内側の「ループ」” になります。

if の多重度によって break で抜け出すループが変わるわけではないですし、break によって if を抜け出すわけではないので注意してください。

continue

続いて continue について説明していきます。break に比べると使う機会は少ないですが、break と一緒に動作を理解しておきましょう!

スポンサーリンク

continue:ループを1週スキップする

continue は “ループを1週分スキップする” 命令になります。

continue を実行すると、下の図のように実行した continue の位置からループブロックの最後、つまりループの終了を示す }(閉じ括弧)の直前までの処理がスキップされます。

continueの説明図

あくまでもそのループブロックの最後まで処理がスキップされるだけですので、スキップされるのはそのループの週の continue 以降の処理のみになります。スキップ後はループの先頭に戻り、ループ処理が継続して実行されることになります。

この continue は、C言語においてはループをスキップする目的でのみ使用する命令になります。

ですので、continuewhilefor のループの内側で実行されます。ループ外で実行した場合はコンパイルエラーとなります。

また break 同様に、continueif 文と組み合わせて使用します。具体的には、下記のように if 文の条件式に “ループを抜け出す条件” を指定し、それが成立したときに continue を実行してループを抜け出すように記述します。

ループをスキップする条件の指定
while (ループを続ける条件) {
    if (ループをスキップする条件) {
        continue;
    }
    /* 何らかの処理 */
}

continue の使い所

基本的に continueif 文で代替することが可能です。

例えば下記では continue を利用しており、if 文の条件を満たす場合にループブロックの最後に処理が移ることになります。

continueでスキップする例
#include <stdio.h>

int main(void) {

    int i;
    int sum;

    sum = 0;
    for (i = 0; i < 100; i++) {
        if (i % 2 == 0) {
            /* 偶数の場合は以降の処理をスキップ */
            continue;
        }
        sum += i;
    }

    printf("sum = %d\n", sum);

    return 0;
}

ただ、これは別に continue を使わなくても、下記のように if 文の組み方を変更することで同じ動作を実現することができます。

ifでスキップする例
#include <stdio.h>

int main(void) {

    int i;
    int sum;

    sum = 0;
    for (i = 0; i < 100; i++) {
        if (i % 2 != 0) {
            /* 奇数の場合のみ足し算を実行 */
            sum += i;
        }
    }

    printf("sum = %d\n", sum);

    return 0;
}

この例だけでなく、continue でスキップする処理は全て if 文で代替することが可能です。

そんな continue ですが、全く使わないということはありません。

continue を利用するかどうかは、結局は “ソースコードの読みやすさ” によって決まると思います。

例えば、下記のように if 文が複数重なってネストが深くなるような場合は、

ifでスキップする例2
#include <stdio.h>

int main(void) {

    int i;
    int count;
    int a[2000];

    for (i = 0; i < 2000; i++) {
        a[i] = i - 1000;
    }

    count = 0;
    for (i = 0; i < 2000; i++) {
        if (a[i] >= 0) {
            if (a[i] < 500) {
                if (a[i] % 2 == 0) {
                    if (a[i] % 10 != 0) {
                        count++;
                    }
                } 
            }
        }
    }

    printf("count = %d\n", count);

    return 0;
}

下記のように continue を利用することでネストを浅い状態で同じ動作を実現することができます。

continueでスキップする例2
#include <stdio.h>

int main(void) {

    int i;
    int count;
    int a[2000];

    for (i = 0; i < 2000; i++) {
        a[i] = i - 1000;
    }

    count = 0;
    for (i = 0; i < 2000; i++) {
        if (a[i] < 0) {
            continue;
        }

        if (a[i] >= 500) {
            continue;
        }

        if (a[i] % 2 != 0) {
            continue;
        }

        if (a[i] % 10 == 0) {
            continue;
        }

        count++;
    }

    printf("count = %d\n", count);

    return 0;
}

おそらくこっちの方がソースコードとしては読みやすいと感じる人が多いのではないかと思います。

また、難しい・複雑な条件式を書くような場合でも、continue を利用すれば都度スキップすることができるため、各条件を分離して独立したものと考えることができます。ですので、上記の if でスキップする例のように “各条件を複合して考えると難しくなる” 場合も、各条件を独立に考えることができるのでソースコードも書きやすくなります。

こんな感じで、continue の使い所は、ループ内でのスキップする処理を if 文だけで書くとソースコードが読みにくくなってしまう時・下記にくくなってしまうだと思います。

continue 利用時の注意点

前述の通り、continue を実行すると continue を実行した位置からループブロックの最後までの処理がスキップされることになります。

この時に、必要な処理までスキップしないように注意が必要です。特に while ループの中で continue を実行する場合、必要な値のインクリメントまでスキップしてしまうことが多いので注意してください。

例えば、下記は 099 の整数の足し算を while ループにより実現しています。

足し算を行うwhileループ
#include <stdio.h>

int main(void) {

    int i;
    int sum;

    sum = 0;
    i = 0;
    while (i < 100) {
        sum += i;
        i++;
    }

    printf("sum = %d\n", sum);

    return 0;
}

これに対して、整数が奇数の場合に continue で足し算をスキップするようにしたものが下記になります。

偶数のみ足し算を行うwhileループ?
#include <stdio.h>

int main(void) {

    int i;
    int sum;

    sum = 0;
    i = 0;
    while (i < 100) {
        if (i % 2 == 1) {
            /* 奇数の場合は足し算をスキップ */
            continue;
        }
        sum += i;
        i++;
    }

    printf("sum = %d\n", sum);

    return 0;
}

continue を行うようにしたことで整数が奇数の場合に足し算がスキップされるので、099 の整数の偶数のみの足し算が行われるようになったと感じる方もおられるかもしれません。

ですが、上記のソースコードでは while ループが無限に実行され、プログラムが終了することさえできません。

これは、continue により変数 i のインクリメントまでスキップされているのが原因です。上記のループの場合、i の値が一度奇数になってしまうと、それ以降ずっと i のインクリメントがスキップされることになるので、i1000 以上にならずに無限ループになってしまいます。

したがって、099 の整数の偶数のみの足し算を行うループにするためには、continue 実行時にも変数 i のインクリメントが実行されるようにする必要があります。

偶数のみ足し算を行うwhileループ
#include <stdio.h>

int main(void) {

    int i;
    int sum;

    sum = 0;
    i = 0;
    while (i < 100) {
        if (i % 2 == 1) {
            /* continue前にインクリメント */
            i++;
            /* 奇数の場合は足し算をスキップ */
            continue;
        }
        sum += i;
        i++;
    }

    printf("sum = %d\n", sum);

    return 0;
}

一方で、for ループの場合は、099 の整数の偶数のみの足し算を行うループは下記で実現することが可能です。while ループの時のように continue 実行後のインクリメントが不要な点がポイントです。

偶数のみ足し算を行うforループ
#include <stdio.h>

int main(void) {

    int i;
    int sum;

    sum = 0;
    for (i = 0; i < 100; i++) {
        if (i % 2 == 1) {
            /* 奇数の場合は足し算をスキップ */
            continue;
        }
        sum += i;
    }

    printf("sum = %d\n", sum);

    return 0;
}

for 文の変化式(上記の i++)はループブロック終了後、つまりループ内の最後の処理が実行された後で実行されます。したがって、continue では for 文の変化式(上記の i++)の処理がスキップされることがありません。

なので、for ループの場合、while ループの時のように continue 実行後のインクリメントは不要になります。逆に実行すると余分にインクリメントしてしまうのでプログラムの動作がおかしくなります。

continue を実行すると、その continue を実行した位置からループブロックの最後までの処理がスキップされます。これは for ループの場合でも while ループの場合でも同じです。

ただし、上記の例のように、continue でスキップされる処理自体は異なる可能性があります(上記の例であれば i++ のスキップの有無に違いがあった)。

continue で必要な処理までスキップされないように、どの処理がスキップされるのかをしっかり考えて continue を利用するようにしてください。

特に for 文での continue に慣れてくると、continue を実行するとインクリメントも勝手に実行されると勘違いしがちなので注意してください。

また、break と同様の話なので解説は省略しますが、continue の効果があるのは、その実行された continue から見て “一番内側のループに対してのみ” という点も continue 使用時の注意点となります。

スポンサーリンク

まとめ

このページでは、C言語における break と continue について解説しました!

各命令を一言で表すと下記のようになります。

  • break:ループを抜け出す
  • continue:ループ1周スキップする

breakとcontinueの説明図

特に break は無限ループを抜け出す場合や、もうループしても意味がなくなった時にループを抜き出すような際によく使います。

continueif 文の組み方を変えるだけで同様の動作を実現できますが、if 文だけだとネストが深くなる、条件式が複雑になるような場合には continue を利用して読みやすいソースコードにできないかどうか検討してみても良いと思います!

多重ループにおいても break で抜け出しすループや continue でスキップするループは一番内側のものになります。

多重ループを一気に抜け出すようにするためには工夫が必要なので注意してください。

これらの breakcontinue を利用することでソースコードが簡潔になったり分かりやすいソースコードにすることも可能です。

ただ、この2つの動作は混同しがちですので、是非このページで解説した内容を覚えておいてください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です