再帰: 自分を呼ぶ関数
マトリョーシカのような構造。アルゴリズムの基礎。
再帰
関数が自分自身を呼び出すこと。
基底条件
再帰呼び出しを止めるための条件分岐。必須。
スタックオーバーフロー
関数呼び出しが深すぎてメモリが枯渇するエラー。
再帰の仕組み
関数の中で、自分自身を呼び出すことを「再帰」と呼びます。無限ループに陥らないために、必ず 「基底条件(Base Case)」という停止条件が必要です。
「問題を少しずつ小さくして、解けるサイズまで分割する(分割統治法)」という考え方に基づいています。木構造の探索やソートアルゴリズムなどで威力を発揮します。
再帰の書き方
// 階乗 (Factorial) の再帰// n! = n * (n-1)!
int factorial(int n) { // 1. 基底条件 (これがないと止まらない) if (n <= 1) return 1;
// 2. 再帰ステップ (問題を小さくして自分を呼ぶ) return n * factorial(n - 1);}
int main(void) { printf("%d\n", factorial(5)); // 120 return 0;} Tip: 再帰は「関数呼び出しのスタック」を積み上げます。深すぎるとクラッシュします。
実践テクニック
Stack Overflow
再帰の停止条件を忘れると、メモリ(スタック領域)を使い果たしてプログラムが強制終了します。これが有名なエラー「Stack Overflow」の語源です。
// Stack Overflow の例void infinite() { int a[1000]; // メモリを消費 printf("Running...\n"); infinite(); // 自分を呼び続ける}
// 実行すると...// セグメンテーション違反 (Segmentation fault)// スタック領域を使い果たしてクラッシュするいつ使うべきか
ディレクトリ探索やHTML解析など、「階層の深さがわからないデータ」を扱うときに再帰は最強の武器になります。逆に、単なるループ(1から10まで足すなど)は <code>for</code> 文で書く方が高速で安全です。
演習課題
課題1: カウントダウン
整数 n を受け取り、n, n-1, ... 0 と表示して最後に "Liftoff!" と表示する再帰関数を作成してください。
解答例を見る
void countdown(int n) { if (n == 0) { printf("Liftoff!\n"); return; } printf("%d\n", n); countdown(n - 1);}合格ライン
基底条件(停止条件)を書ける
スタックオーバーフローの原因を説明できる