
前回はプロジェクト「0170_for」を新しく作り、繰り返し処理を行うfor文についてお話ししました。
今回は、新しくプロジェクト「0180_nested_loop」を作り、繰り返し処理を入れ子にして書いたときの処理の流れについてお話します。この書き方を知っていることで、2Dや3Dゲームのデータ処理によくある、地形生成などに使われている繰り返し処理の流れの基礎がわかるかと思います。
なお、C言語の繰り返し処理は下の順番でお話ししています。
繰り返し処理をくみこんだソースコードを実際にプログラムを動かして結果を見てみましょう。プロジェクト「0180_nested_loop」を新しく作成し、ソースコード「NestedLoop.c」を作成してみてください。
#include <stdio.h>
int main() {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 10; x++) {
printf("#");
}
printf("\n");
}
}
このコードを実行してみるとこんな結果になったかと思います。
##########
##########
##########
##########
横方向に 10 個、縦方向に 4 個ぶんの「#」が表示されたかと思います。
前回までで for 文などの繰り返し文をお話しました。繰り返し文の中にさらに繰り返し文が入っています。このように繰り返し処理の中に繰り返し処理が入っているような構造をネスト構造(Nest) と呼びます。
どのような処理の流れになるか、見てみましょう。
まず2つの for 文の実行範囲を赤と青で分けてみましょう。
for 文のネスト構造
赤色で囲んだ外側の for 文の中に、青色の for 文が入っています。
青色の for 文はどのような処理をしているかを確認してみます。
4~6行目までの for の中身は下の部分ですね。
for (int x = 0; x < 10; x++) {
printf("#");
}
まず for 文に入るとき、変数 x に 0 を代入しています。
条件は「x < 10」で、その間は繰り返し処理を実行することになります。
そして、繰り返し完了時に、「x++」を行い、 x の中身を 1 増やしています。
つまり、このfor文は、printf("#"); を 10 回行う処理となっていますね。
先のどの赤色と青色で分けたループ処理の中身に当てはめてみるとわかりやすくなるかと思います。
for文のネスト構造を見やすく置き換え
赤色の for 文の繰り返し処理の中身は、 「printf("#"); で 記号#シャープを 10 回表示する処理」と「printf("\n"); で改行する処理」 となります。 これを y < 4 の間繰り返すことになります。
for の繰り返し完了時の処理で y++ しているので、4 回繰り返していることになりますね。 これで、横に 10 個 、縦に 4 個のシャープ記号(#)が表示されるプログラムができました。
ネスト構造の中で break や continue 文を使った時はどのような流れになるでしょうか。
break文は while文や for文などの繰り返し文や switch 文の中で使うことができます。
これらの文がネスト構造になっているとき、break 文を使うと、今いる場所の while や for の処理から一つ外側に抜けることができます。
下のようなイメージです。
for文のネスト構造の中でbreak文
今回のサンプルプログラムで見てみましょう。ハイライトの行(5~8行目)に if 文と break を追加しています。
#include <stdio.h>
int main() {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 10; x++) {
if (y == 1) {
printf("<-break!");
break;
}
printf("#");
}
printf("\n");
}
}
実行すると以下のような結果になります。
##########
<-break!
##########
##########
結果の2行目が変わっていますね。
5~8行目は if 文で囲まれています。 if ( y == 1 ) { ‥‥ } とあるので、 y が 1 の時のみ実行される処理となります。
外側の for ループ(3~12行)が 2 回目に入ったとき、 y は 1 になっていますね。
そして、内側の for ループ(4~10行)を実行しようとしたとき、 if ( y == 1 ) { ‥‥ } の条件に合致され、実行されます。
if 文の中で printf関数により「<-break!」というメッセージが表示されたのち、break文により、 内側の for ループから 抜け出します。
その後、11行目の printf関数で改行され、外側の for ループが継続されます。
continue文についても break 文と同じで、今いる場所の for文や while文に対しての処理となります。こちらも、今回のサンプルプログラムに continue を追記したものをご参考までにのせておきます。
#include <stdio.h>
int main() {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 10; x++) {
if (y == 1) {
printf("<-break!");
break;
}
if (x == 5) {
printf("-");
continue;
}
printf("#");
}
printf("\n");
}
}
9~12行目のハイライトした箇所に新しく if 文と continue文を追加しています。
実行するとこのような結果になります。
#####-####
<-break!
#####-####
#####-####
結果で表示されている 10列 × 4行の「#」について、の6列目が「-」になっています。
今回追加した「if ( x == 5 )」の条件に合致するような箇所だけ、「-」を表示し、continue 文を実行しているためこのような結果となっています。
ネスト構造を重ねて書く必要のあるプログラムはたくさんあります。ゲームでも2Dや3Dの画像関連のプログラムや、データのチェックなどで頻繁に使われます。
例えば、3Dのデータで存在する (x,y,z) 領域全てに対しての処理などは for 文を3つ重ねて書いたりすることが多いですし、Unity や UnrealEngine 等のゲームエンジン画面表示時の Shader (描画の加工をする機能)の部分でも頻繁に使われたりします。
深~いネスト構造の中で、重たい処理をすると、それだけ繰り返し実行される処理が増えるのでゲーム全体がカクカクで重たくなったりします。
また、ソースコードが人間の目で読みづらくなるので、深いネスト構造を作るときは本当に必要なのかを考える必要がありますので、便利なのですが注意して扱う必要があります。
今回はここまで。おつかれさまでした。
更新日 | 更新内容 |
---|---|
2018/7/31 | 初版公開 |
2018/11/26 | アイキャッチ画像、トップ画像を追加 |
コメント、ありがとうございます。
ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。
Twitter:@NodachiSoft_jpお名前:以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください
お名前: