for文にfor文を代入してみる   for文ネスト(入れ子)構造はどうなっているの?

ソーラー「ここまできたらfor文もアレンジしてみよう。


for文につづくブロック{}のなかに


for文を書き込んでプログラムを構成してコンパイルしてみるよ。


#include <stdio.h>

int main(void){

int a;

int b;


for(a=1;a<3;a++){

for(b=1;b<5;b++)

{

printf("%d回目のご飯はNouvel de かつおです\n",b);

}

}

return 0;

}


コンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


たまにこのような


for文ブロックにfor文が代入してあるプログラムをみかけるけど


原理はとても簡単だね。


この場合


まず


for(a=1;a<3;a++){}のブロック{}のなかに記述されている


for(b=1;b<5;b++)

{

printf("%d回目のご飯はNouvel de かつおです\n",b);

}


により


printf("%d回目のご飯はNouvel de かつおです\n",1);

printf("%d回目のご飯はNouvel de かつおです\n",2);

printf("%d回目のご飯はNouvel de かつおです\n",3);

printf("%d回目のご飯はNouvel de かつおです\n",4);


が形成されます


それが


for(a=1;a<3;a++)文によって


a=1のとき


printf("%d回目のご飯はNouvel de かつおです\n",1);

printf("%d回目のご飯はNouvel de かつおです\n",2);

printf("%d回目のご飯はNouvel de かつおです\n",3);

printf("%d回目のご飯はNouvel de かつおです\n",4);

が実行され


a=2のとき


printf("%d回目のご飯はNouvel de かつおです\n",1);

printf("%d回目のご飯はNouvel de かつおです\n",2);

printf("%d回目のご飯はNouvel de かつおです\n",3);

printf("%d回目のご飯はNouvel de かつおです\n",4);


が実行されます。


つまり


printf("%d回目のご飯はNouvel de かつおです\n",1);

printf("%d回目のご飯はNouvel de かつおです\n",2);

printf("%d回目のご飯はNouvel de かつおです\n",3);

printf("%d回目のご飯はNouvel de かつおです\n",4);

printf("%d回目のご飯はNouvel de かつおです\n",1);

printf("%d回目のご飯はNouvel de かつおです\n",2);

printf("%d回目のご飯はNouvel de かつおです\n",3);

printf("%d回目のご飯はNouvel de かつおです\n",4);


が実行されることになります


これらのプログラムが実行されて


コンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


がコマンドプロンプト画面に表示されるわけです。」


アレサ 「そのような仕組みとなっているので


最初に入れ子になっている


for(b=1;b<5;b++)文により


printf("%d回目のご飯はNouvel de かつおです\n",b);

が実行されて


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


の文字だけが


次のように プログラムのなかにのこり


#include <stdio.h>

int main(void){

int a;

int b;

for(a=1;a<3;a++){

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

}

return 0;

}


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


はprintf関数もついてないし


コンパイルできるプログラムにならない・・・


プログラムを実行できないのでは?


そのような事態にはならないのです。


つまり


for{}には


ブロック{}内の


命令文を複数生成するという働きがあり


命令文が複数生成されてから


その命令文は実行されます。


命令文が複数生成される前に


ブロック{}内の命令文が実行されることはありません。」


ソーラー 「


for文ネスト(入れ子)構造はこれにて終了となりま~~す😊」






























































ソーラー「 みなさん こんにちは


第2部の開始です。


では  では


下のプログラムはどう動くように設計されているのかな?


ちょっと実験してみる? 


#include <stdio.h>

int main(void){

int a;

for(a=1;a<3;a++){

for(a=1;a<5;a++)

{

printf("%d回目のご飯はNouvel de かつおです\n",a);

}

}

return 0;

}


このプログラムは先ほどのプログラムとなにが違うのかな?


じっと観察してみましょう。




int b;がなくなって


入れ子のfor文にも変数aをつかっていますね。


このような変数aの使い方は


for文ネスト構造では普通はしません。


こんがらがっちゃいます。



このプログラムをコンパイルするとどうなるかな?


コンパイル結果は


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となり


先ほどの

1つ目のfor文には変数aを

2つ目のfor文には変数bを


もちいた場合とは違うコンパイル結果になったね。


いったい


どういう仕組みになってるんだろう?」


 

アレサ

「まず、内部の入れ子になっている


for(a=1;a<5;a++)

{

printf("%d回目のご飯はNouvel de かつおです\n",a);

}

により


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


が実行されているのはわかります。


次に

for(a=1;a<3;a++){}がどのように作用するかですが・・・」


ソーラー「


ふつうはfor(a=1;a<3;a++)により 2回


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


が繰り返され


コンパイル結果

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となるよね。」


てんC「それが


コンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となっています。


for(a=1;a<3;a++)の部分を


for(a=2;a<3;a++)

for(a=1;a<5;a++)


と変形しても


コンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となっています。


そう1回しか繰り返されていません。??


for(a=1;a<3;a++)を

for(a=1;a<6;a++)に変更しても


コンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となっています。


さらに

for(a=1;a<3;a++)を

for(a=1;a<7;a++)に変更するとコンパイル結果は・・・



コンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


このように無限に


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


が繰り返されていきます


???



a<3からa>3へ


普通は一回も実行されないfor文


for(a=1;a>3;a++)に


かえると


コンパイル結果は


続行するには何かキーを押してください_


となり


命令文は通常通り実行されていない・・・です。」


ソーラー 「条件式a>3をとりのぞいて


無限に命令文を繰り返す


for(a=1;;a++)とした場合は


コンパイル結果は


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

となり


普通どおりに命令文が無限に実行されていきますね。


どうも


うまく機能してないのは


条件式a<数値が関係してくるときのようです。


つまり

有限回命令を繰り返すfor文のときか・・・


どうなってるんだろ?


なぜa<1,a<2,a<3,a<4,a<5,a<6

のときは


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

を1回だけ表示し


a<7になると突然

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

を無限にくりかえすのか?


なんで???・・・」


アレサ、てんC


「つまり この for文の入れ子構造は・・・」



















アレサ てんC ソーラー「規則性なし!!!


わははははっ うふ、うふふ 楽しいね。」


ソーラー 「本当に面白いなぞなぞだね~。


開発者がプログラム言語の仕組みを自由につくるので


どのような仕組みもありえるんだけど


それにしても規則性が全く見抜けない。


コンピューターは規則ただしく命令文を実行してるはずだから


多分、何かの規則にしたがってこのようなコンパイル結果を


はじきだしてるはずなんだけど・・・


面白いね。


開発者の知らないところで


命令文が影響しあっているのかもしれない。


これが自然現象ならとても面白い現象がおこってる・・・。



これは パズルとしては とてもよくできているね。


とにかく


for文入れ子構造では

内部の入れ子のfor文と外側のfor文に使われる変数を


このプログラムのように同じ変数aを使ってはいけないんだね

👇

#include <stdio.h>

int main(void){

int a;

for(a=1;a<3;a++){

for(a=1;a<5;a++)

{

printf("%d回目のご飯はNouvel de かつおです\n",a);

}

}

return 0;

}


正しくは


#include <stdio.h>

int main(void){

int a;

int b;


for(a=1;a<3;a++){

for(b=1;b<5;b++)

{

printf("%d回目のご飯はNouvel de かつおです\n",b);

}

}

return 0;

}

と記述するか


#include <stdio.h>

int main(void){

int a;


for(a=1;a<3;a++){

int b;

for(b=1;b<5;b++)

{

printf("%d回目のご飯はNouvel de かつおです\n",b);

}

}

return 0;

}                       


と記述しなければなりません。


めでたし、めでたし」


マックス「えっなんで?👆の2つのようなプログラムの書き方が


あるのか わからないぞ?」


ソーラー「えっ


なんで👆の2つのようなプログラムの書き方が


あるのか・・ですか


私に注目したい・・・と


そういうことですか?」


マックス「??それも ちょっと 違うんだが・・・」


アレサ「そのことについては


複数のローカル変数のスコープ(ローカル変数の使用可能な範囲)について考察してみましょう


のエピソードで詳しく述べられていますの


よんでいただければ


お分かりになられますが全く難しいことではありませんの」


ソーラー「お楽しみにね


そこをお読みになれば ほんと簡単にわかることなんだけど


そこにたどりつくまでのお楽しみにする?


それとも 今すぐ そのエピソードを読んでみる?


あとは読者さんにおまかせかな?」























ソーラー 「みなさん 第3部の開始です


先程のプログラム


#include <stdio.h>

int main(void){

int a;

for(a=1;a<3;a++){

for(a=1;a<5;a++)

{

printf("%d回目のご飯はNouvel de かつおです\n",a);

}

}

return 0;

}

では


コンパイル結果

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となり


予想していたコンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となりませんでした。


そこで


プログラムを次のように変形すると


#include <stdio.h>

int main(void) {

int a;

for (a = 1; a<3; a++) {

int a;/*ここにint a;と記述します*/

for (a = 1; a<5; a++){

printf("%d回目のご飯はNouvel de かつおです\n", a);

}

}

return 0;

}


コンパイル結果


1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです

1回目のご飯はNouvel de かつおです

2回目のご飯はNouvel de かつおです

3回目のご飯はNouvel de かつおです

4回目のご飯はNouvel de かつおです


となり予想通りの


コンパイル結果がえられます。


このプログラムはどのようにかきかえられたのかというと


書き換え前の


for (a = 1; a<3; a++) {

for (a = 1; a<5; a++){

printf("%d回目のご飯はNouvel de かつおです\n", a);

}

}


👆このfor文2重入れ子の中に


int a;を記述することにより


for (a = 1; a<3; a++) {

int a;/*ここにint a;と記述します*/

for (a = 1; a<5; a++){

printf("%d回目のご飯はNouvel de かつおです\n", a);

}


書き換え前は


for (a = 1; a<5; a++){

printf("%d回目のご飯はNouvel de かつおです\n", a);

}


for (a = 1; a<3; a++)により2回繰り返していたのから


書き換え後は

変数宣言int a;も含めた


int a;

for (a = 1; a<5; a++){

printf("%d回目のご飯はNouvel de かつおです\n", a);

}



をfor (a = 1; a<3; a++)により2回繰り返した


というわけです。



一体これは


どういうことなのでしょうか?


なにが行われているのかさっぱりわかりませんね。



ポイントは


int a;を新たに記述したことにあります。


#include <stdio.h>

int main(void) {

int a;👈

for (a = 1; a<3; a++) {

int a;☜👈☜👈ここに新たなint a;を記述したわけです。

for (a = 1; a<5; a++){

printf("%d回目のご飯はNouvel de かつおです\n", a);

}

}

return 0;

}


この

int a;👈と

int a;☜👈☜👈は

実はコンピュータにとっては違う変数として認識されており


#include <stdio.h>

int main(void) {

int a;👈

for (a = 1; a<3; a++) {

int a;☜👈☜👈ここに新たなint a;を記述したわけです。

for (a = 1; a<5; a++){

printf("%d回目のご飯はNouvel de かつおです\n", a);

}

}

return 0;

}



#include <stdio.h>

int main(void) {

int a;👈

for (a = 1; a<3; a++) {

int b;☜👈☜👈ここに新たなint a;を記述したわけです。

for (b = 1; b<5; b++){

printf("%d回目のご飯はNouvel de かつおです\n", b);

}

}

return 0;

}


が行われているのと等しくなるのです


なぜこのようなことが起こるのか


たびたび不思議なことが起こりますね。


このことについては


複数のローカル変数のスコープ(ローカル変数の使用可能な範囲)について考察してみましょう


のエピソードで詳しく説明されています


お楽しみにね。」


マックス「これがわかれば 結構プログラムに詳しくなりそうじゃないか


は~ははははははははははっはは」



  • Twitterで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます