2011年3月4日金曜日

nScript講座 第15.5回


同じ日に二つも講座を書くのは気が引けます。
しかも続き物の予定を崩してまで二つ目を書くのですから。

と、いうわけで懐かしの「.5」講座です。
他の言語にも通じる、ちょっぴり大切だけど知ってる人にとっては何の必要もない
この講座ですが、知らない人はちゃんと見ておかないと痛い目に遭います。



ではいきましょう。

//////////////////////////////////
Function main() {
     main();
}
//////////////////////////////////

以上がサンプルです。
短いですね。では書いて実際に実行してみましょう。
もれなくプログラムが強制終了します。それもnScript本体が。

何故でしょうか?
ではひとまず、今回行っていることを日本語に書き出してみましょう。

1、main関数スタート
2、main関数を、main関数を呼び出し元として呼び出す
3、1へ飛ぶ

という、繰り返しになります。
main関数がどんどんどんどんどんどんどんどん積み重なっていきます。
本当にどんどんどんどんどんどんどんどん積み重なるので、プログラムは

「もう嫌だ!!!こんな強制労働やってられねえ!!!」

といって強制終了しちゃうわけです。

関数内で定義されたローカル変数は、メモリの「スタック領域」という所に
確保されていきます。
そして関数を抜けるときにそこの領域ごと消すので、ローカル変数は消えるのです。
またスタック領域には関数の呼び出し元の情報だけでもどんどん積みあがっていきます。
と、いうわけで何回も何回も呼び出していると、このスタック領域があふれてしまい、
最終的にプログラムがさよならするわけです。

これを「スタックオーバーフロー」といいます。

また、関数内からまた自分自身を呼び出す事を「再帰呼び出し」といいます。

Windowsだと、確かApplication Errorとして強制終了するはずです。
(Brainでは「異常が発生しました.....」というやつが表示されてリセットさせられます。)

では、こんな危険な構造があるのでしょう?

例えば今まで繰り返しの構造を作るとしたら、while文を使っていましたよね?
今回のプログラムをみてみると、繰り返し構造になっていますね?
つまりは、再帰呼び出しは繰り返しを作るためのものなのです。
どうしてもこいつを使わないと実現できないという繰り返しは、おそらくありません。
しかしいざ使ってみると、便利な事が多いんですね。
以下にその例を示します。

/////////////////////////////
Function main() {
   a=func(3);
   puts(a);
}

Function func(n) {
   if (n==0) return 1;
   return func(n-1)*n;
}
/////////////////////////////

上のプログラムのfunc関数は、整数nを入力としてnの階乗を出力する関数です。
n!と、数学では記述しますね。
4!
=4*3*2*1
=24
と解きます。
階乗は、上のように数を1ずつ減らしていきながら最後1になるまで掛けるものです。
よーく順番を追ってみてください。
最後0になるまで再帰呼び出しを繰り返して、値を返しています。

階乗の求め方が、再帰呼び出しの一番有名な具体例です。

良さも一応あるんです。
でもPineは絶対に使いませんけどね。怖いですし。
よっぽど長い記述になっちゃったら、これに変えて様子を見る感じです。
ですので皆さんも、状況に応じて、この再帰呼び出しを悪用してください←?

ボタンを押したら突然アプリケーションエラー...みたいなプログラムも面白そうです。
ね?人の迷惑になるプログラムは簡単に作れるのです。

それはいいとして。
それほど長くなりませんでしたね。今回の講座はこれにて終わりー。

4 コメント:

よつ さんのコメント...

悪用w
無限ループってこわいですね!
前にzaurusでターミナルのbashでshを呼び出してshでbashを呼び出すようなことをしてしまって、大変なことになりましたw
それだけにも気づくのに時間がかかりました...

Pine さんのコメント...

おお!
シェルスクリプトやってるんですか!
あれは、、なんか面倒くさくて挫折しますたw

悪い動きをするプログラム書いても絶対に上達はしないと思います。
すくなくともPineはそう考えていますから。。
まあ、使おうと思えば結構使えそうですよね。再帰呼び出しは。

が、

僕はwhile文しか使いません←w

よつ さんのコメント...

いえ、やってないですw
微妙にいじってみただけで学んですらいませんwコマンドとパスを書き加えただけで..

そういえばwhileでもループできますもんね、故に僕にはその「使おうと思えば結構使えそう」がわかりませんw

Pine さんのコメント...

ネット徘徊してるとわかりますが.....

下手すると行数が1/3くらいになることもあるんですよ。こいつを使うと。
ですから、「知っているべき」ではあるでしょうね。

コメントを投稿

Related Posts Plugin for WordPress, Blogger...

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Walgreens Printable Coupons