第9講 関数の再帰的使用
第3話 難解なプログラムの解読
コード再掲
#include<stdio.h>
int f(int a);
int main() {
printf("1から10までの和は%dです。\n",f(10));
return(0);
}
int f(int a) {
int w;
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
return(w);
}
解説
最初に、main()は1から10までの和は何とf(10)によって関数f(10)に問い合わせています。
以下、
最初の人形(f(10)本体)は、f(a - 1)によって『f(9)の正体は何と』f(10)の分身f(9)に問い合わせます。
f(9)の正体とは1+2+3+4+5+6+7+8+9の答えです。
f(9)は、f(a - 1)によって『f(8)の正体は何と』f(9)の分身f(8)に問い合わせます。
f(8)の正体とは1+2+3+4+5+6+7+8の答えです。
f(8)は、f(a - 1)によって『f(7)の正体は何と』f(8)の分身f(7)に問い合わせます。
f(7)の正体とは1+2+3+4+5+6+7の答えです。
f(7)は、f(a - 1)によって『f(6)の正体は何と』f(7)の分身f(6)に問い合わせます。
f(6)の正体とは1+2+3+4+5+6の答えです(以下同様)。
f(6)は、f(a - 1)によって『f(5)の正体は何と』f(6)の分身f(5)に問い合わせます。
f(5)は、f(a - 1)によって『f(4)の正体は何と』f(5)の分身f(4)に問い合わせます。
f(4)は、f(a - 1)によって『f(3)の正体は何と』f(4)の分身f(3)に問い合わせます。
f(3)は、f(a - 1)によって『f(2)の正体は何と』f(3)の分身f(2)に問い合わせます。
f(2)は、f(a - 1)によって『f(1)の正体は何と』f(2)の分身f(1)に問い合わせます。
f(1)は、f(a - 1)によって『f(0)の正体は何と』f(1)の分身f(0)に問い合わせます。
最後の分身f(0)にたどり着いて、その正体がはじめてわかります。
if (a -1 >= 0)w=f(a - 1); else w=0;
の否定部分によってw=0になり、
w+=a;
によって、
w=0+0=0;
f(0)の正体が0であることがわかります。
この0が
return(w);
によって、f(1)に返されます。
f(1)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=0;
w=0+1;
を辿りf(1)の正体が1であることがわかり、
return(w);
によって、f(2)に1が返されます。
f(2)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=1;
w=1+2;
を辿りf(2)の正体が3であることがわかり、
return(w);
によって、f(2)に3が返されます。
f(3)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=3;
w=3+3;
を辿りf(3)の正体が6であることがわかり、
return(w);
によって、f(4)に6が返されます。
f(4)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=6;
w=6+4;
を辿りf(4)の正体が10であることがわかり、
return(w);
によって、f(5)に10が返されます。
f(5)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=10;
w=10+5;
を辿りf(5)の正体が15であることがわかり、
return(w);
によって、f(6)に15が返されます。
f(6)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=15;
w=15+6;
を辿りf(2)の正体が21であることがわかり、
return(w);
によって、f(7)に21が返されます。
f(7)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=21;
w=21+7;
を辿りf(7)の正体が28であることがわかり、
return(w);
によって、f(8)に28が返されます。
f(8)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=28;
w=28+8;
を辿りf(8)の正体が36であることがわかり、
return(w);
によって、f(9)に36が返されます。
f(9)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=36;
w=36+9;
を辿りf(9)の正体が45であることがわかり、
return(w);
によって、f(10)に45が返されます。
f(10)では
if (a -1 >= 0)w=f(a - 1); else w=0;
w+=a;
の2行から
w=45;
w=45+10;
を辿りf(10)の正体が55であることがわかり、
return(w);
によって、main()に55が返されます。
以上の長い過程を得てはじめて1+2+3+4+5+6+7+8+9+10の正体がつかめるのです。
以上を簡単にまとめると
main()→f(10)→ f(9)→f(8)→f(7)→f(6)→f(5)→ f(4)→f(3)→f(2)→f(1)→f(0)
と遡及していって、一番小さい人形(一番内側の人形)にたどり着いて自分の一番奥深くの正体が0であることを発見します。
この後は逆遡及を通して、
f(0)→ f(1)→f(2)→f(3)→f(4)→f(5)→ f(6)→f(7)→f(8)→f(9)→f(10)→main()
main()にたどり着くのですが、一番奥深い自分の本質0は、
0→0+1=1→1+2=3→3+3=6→6+4=10→10+5=15→15+6=21→21+7=28→28+8=36→36+9=45→45+10=55
と加工されていって、55に変身を遂げて、main()に戻されるのです。
自分探しの長い旅の末に発見した自分の一番奥深い本質が0すなわち空っぽであることを発見するとは恐ろしいことです。
ですが、実は一番小さい人形の0が自分の本質なのではなく、
遡及と逆遡及の過程こそが本当の自分であるというわけです。
結果ではなく努力する過程こそが自分の本当の本質であり姿なのです。
ですから、一番内側の人形の本質が0であることを嘆くことはないのです。
自分のもっとも内なる本質を探し出す遡及が、より内なる人形への旅ですし、
逆遡及がより外なる人形への旅です。
一番内側の人形にたどり着きターンして一番外側の人形に戻ってきたときに、
一番外側の人形はmain()から仕事を依頼された直後とは異なる姿になっています。
遡及と逆遡及によって、内容が豊かになり、はじめてmain()の質問に答えられるのです。
途中の人形もそうです。
内側まで進んで戻ってきたときに、はじめて1つ外側の人形の質問に答えられるのです。
1+2+3+4+5+6+7+8+9+10を求めるには、
1+2+3+4+5+6+7+8+9の答えを知らなければなりません。
それを求めるためには、
1+2+3+4+5+6+7+8の答えを知らなければなりません。
・
この旅が遡及です。
f(0)にきて自分の一番奥深い本質が0であることを知ります。
すると、f(1)は0+1=1であることを知ります。
以下f(2)は1+2=3
f(3)は3+3=6
・
この旅が逆遡及です。
遡及と逆遡及の運動・過程を通して、はじめて人形の内容が豊かになるのです。
過程(体験)を通して内容が豊かになるのは人間も同じです。
結果ではなく、過程こそが本質であるというのが、
ヘーゲルやマルクスの考え方なのです。
結果オーライという考え方は、資本主義的考え方なのです。
本来は、試合の結果ではなく試合の内容すなわち経過こそが大事なはずです。
ですから、結果こそすべてという考え方は特殊歴史的な例外的な考え方なのです。
さて、この難解なプログラムを改良して階乗を求めましょう。
5!は5の階乗と読み、1×2×3×4×5を表します。
何の階乗を求めるのかはコンソール画面においてキーボードから取得させて、
実行画面が
これはa!を求めるプログラムです。aに値を入れてエンターして下さい。
a=10
10!=3628800
となるプログラムを組んで下さい。