再帰を理解する秘訣は、スタックを理解することです。
私は2行目で、という関数を使用しmain
ています。すべてのローカル変数はスタックフレームに格納されています。
+------------------+
| main() variables | The stack frame
+------------------+
次に、を呼び出すとfib(3)
、コンピューターは現在の位置(EIP)をスタックにプッシュし、fib用の新しいスタックフレームを作成して追加します。一番上のスタックフレームにしかアクセスできません。
+------------------+
| fib() n = 5 | Top of stack (current frame)
+------------------+
| EIP: main @ 2,1 |
+------------------+
| main() variables | Bottom of stack
+------------------+
の4行目では、再度fib
呼び出さfib
れるため、同じことが再び発生します。
+------------------+
| fib() n = 4 | Top of stack
+------------------+
| EIP: fib @ 4,1 |
+------------------+
| fib() n = 5 |
+------------------+
| EIP: main @ 2,1 |
+------------------+
| main() variables | Bottom of stack
+------------------+
そして、関数が再帰的に呼び出されるときに、これを何度も繰り返します。スタックは何かが戻るまで成長し、その時点で、の2行目でfib
1を返します。これにより、一番上のスタックフレームがポップされて破棄され、保存された実行ポインタに実行が返され、プログラムは中断したところから続行します。
+------------------+
| fib() n = 3 | Top of stack
+------------------+
... etc ...
+------------------+
| EIP: main @ 2,1 |
+------------------+
| main() variables | Bottom of stack
+------------------+
最終的には、呼び出し元の関数に戻ります(または、スタックが大きくなりすぎると、スタックオーバーフローが発生します)。覚えておくべき重要なことは、関数が呼び出されるたびに、すべてのローカル変数を含む新しいスタックフレームが取得され、以前の位置が保存されることです。それが再帰です。
主な問題は、人々に再帰を教える際に、誰もが常にフィボナッチ数列を使用することです。これは、1行に2つの再帰関数呼び出しがあることを意味します。あなたが同意すると確信しているので、これは不必要に混乱します!