for{}文に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);

}

により

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 かつおです

が表示される元になっています)


が生成されているのはわかります。


次に

for(a=1;a<3;a++){}がどのように


ブロック{}内の命令文


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++)により 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);

が繰り返され


プログラムの実行結果


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文


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


かえると


プログラムの実行結果は


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


となり


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


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


無限にfor{}文のブロック{}内の命令文を繰り返す


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;

}


正しくは


外側の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;

}

と記述するか


#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で共有
  • はてなブックマークでブックマーク

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る