このページでは、C言語における break
と continue
について解説していきたいと思います。
これら2つは while
や for
ループ処理において非常に便利な命令です。これらを使いこなすことで様々なループを簡潔に記述することができるようになります。
ただ、慣れないうちは break
と continue
を混同しがちですので、是非このページで break
と continue
の動きの違いや使い所の違いをしっかり理解していただければと思います。
Contents
break
では、まずは最初に break
について解説していきます。
break
に関しては switch
文で使用することもありますが、ここではループ内で使用する break
に焦点を当てて解説を行います。
break
:ループを抜け出す
break
は “ループを抜け出す” 命令になります。
break
を実行すると、下の図のようにループブロックの外側、つまり、ループの終了を示す }
(閉じ括弧)の “外側に” 即座に処理が移ります。
ループ処理が残っている場合でも、それらの処理を中断して即座にループ終了後の処理を実行することが可能です。
ループを抜け出す目的で break
を使用する際には、while
や for
のループの内側で braek
を実行する必要があります。
また break
は、”ある条件が成立したときにループを抜け出す目的” で利用するのが一般的です(常にループを抜け出すように break
してしまうと、それはもはやループではないですよね…)。
なので、基本的に break
は if
文と組み合わせて使用します。具体的には、下記のように if
文の条件式に “ループを抜け出す条件” を指定し、それが成立したときに break
を実行してループを抜け出すように記述します。
while (ループを続ける条件) {
if (ループを抜け出す条件) {
break;
}
}
スポンサーリンク
break
の使い所
break
の使い所の1つが “無限ループを終了させたい” ときです。
特定の条件を満たすまで無限ループで処理を待機したいような場合に、この 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
を利用すれば、その無駄な処理を行うことなくループを抜け出すことができます。
#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
されると勘違いすることが多いので注意してください。
例えば、上記で紹介した探索を2重ループの中で実行する例を考えてみましょう。先ほど同様に配列の中に “1つしか存在しない数値” を探索する場合として考えたいと思います。
#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
にセットするようにし、外側のループでは isFind
が 1
の時に break
を実行するようにすれば、内側の break
が実行された際に外側のループも 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
は、C言語においてはループをスキップする目的でのみ使用する命令になります。
ですので、continue
は while
や for
のループの内側で実行されます。ループ外で実行した場合はコンパイルエラーとなります。
また break
同様に、continue
は if
文と組み合わせて使用します。具体的には、下記のように if
文の条件式に “ループを抜け出す条件” を指定し、それが成立したときに continue
を実行してループを抜け出すように記述します。
while (ループを続ける条件) {
if (ループをスキップする条件) {
continue;
}
/* 何らかの処理 */
}
continue
の使い所
基本的に continue
は if
文で代替することが可能です。
例えば下記では continue
を利用しており、if
文の条件を満たす場合にループブロックの最後に処理が移ることになります。
#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
文の組み方を変更することで同じ動作を実現することができます。
#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
文が複数重なってネストが深くなるような場合は、
#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
を利用することでネストを浅い状態で同じ動作を実現することができます。
#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
を実行する場合、必要な値のインクリメントまでスキップしてしまうことが多いので注意してください。
例えば、下記は 0
〜 99
の整数の足し算を 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
で足し算をスキップするようにしたものが下記になります。
#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
を行うようにしたことで整数が奇数の場合に足し算がスキップされるので、0
〜 99
の整数の偶数のみの足し算が行われるようになったと感じる方もおられるかもしれません。
ですが、上記のソースコードでは while
ループが無限に実行され、プログラムが終了することさえできません。
これは、continue
により変数 i
のインクリメントまでスキップされているのが原因です。上記のループの場合、i
の値が一度奇数になってしまうと、それ以降ずっと i
のインクリメントがスキップされることになるので、i
が 1000
以上にならずに無限ループになってしまいます。
したがって、0
〜 99
の整数の偶数のみの足し算を行うループにするためには、continue
実行時にも変数 i
のインクリメントが実行されるようにする必要があります。
#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
ループの場合は、0
〜 99
の整数の偶数のみの足し算を行うループは下記で実現することが可能です。while
ループの時のように continue
実行後のインクリメントが不要な点がポイントです。
#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
は if
文の組み方を変えるだけで同様の動作を実現できますが、if
文だけだとネストが深くなる、条件式が複雑になるような場合には continue
を利用して読みやすいソースコードにできないかどうか検討してみても良いと思います!
多重ループにおいても break
で抜け出しすループや continue
でスキップするループは一番内側のものになります。
多重ループを一気に抜け出すようにするためには工夫が必要なので注意してください。
これらの break
や continue
を利用することでソースコードが簡潔になったり分かりやすいソースコードにすることも可能です。
ただ、この2つの動作は混同しがちですので、是非このページで解説した内容を覚えておいてください!
オススメの参考書(PR)
C言語学習中だけど分からないことが多くて挫折しそう...という方には、下記の「スッキリわかるC言語入門」がオススメです!
まず学習を進める上で、参考書は2冊持っておくことをオススメします。この理由は下記の2つです。
- 参考書によって、解説の仕方は異なる
- 読み手によって、理解しやすい解説の仕方は異なる
ある人の説明聞いても理解できなかったけど、他の人からちょっと違った観点での説明を聞いて「あー、そういうことね!」って簡単に理解できた経験をお持ちの方も多いのではないでしょうか?
それと同じで、1冊の参考書を読んで理解できない事も、他の参考書とは異なる内容の解説を読むことで理解できる可能性があります。
なので、参考書は2冊持っておいた方が学習時に挫折しにくいというのが私の考えです。
特に上記の「スッキリわかるC言語入門」は、他の参考書とは違った切り口での解説が豊富で、他の参考書で理解できなかった内容に対して違った観点での解説を読むことができ、オススメです。題名の通り「なぜそうなるのか?」がスッキリ理解できるような解説内容にもなっており、C言語入門書としてもかなり分かりやすい参考書だと思います。
もちろんネット等でも色んな観点からの解説を読むことが出来ますので、分からない点は別の人・別の参考書の解説を読んで解決していきましょう!もちろん私のサイトも参考にしていただけると嬉しいです!
入門用のオススメ参考書は下記ページでも紹介していますので、こちらも是非参考にしていただければと思います。
https://daeudaeu.com/c_reference_book/