Turbo C 2.0 允許函數直接或間接呼叫自己,這項機制稱為遞迴。遞迴能將複雜問題分解為同樣結構的子問題,使程式碼極度精簡、邏輯清晰;代價是每層呼叫需消耗堆疊空間,深度過大易導致堆疊溢位。理解「基底條件」與「遞迴步驟」是掌握遞迴的關鍵。
階乘的數學定義天然具備遞迴特性:
0! = 1! = 1n! = n × (n-1)! (n > 1)#include <stdio.h>
#include <conio.h>
unsigned long mul(int n); /* 函數原型:回傳 unsigned long 防溢位 */
int main(void)
{
int m;
puts("Calculate n! n=?");
scanf("%d", &m);
printf("%d! = %lu\n", m, mul(m)); /* %lu 對應 unsigned long */
getch();
return 0;
}
/* 遞迴函數:計算 n! */
unsigned long mul(int n)
{
unsigned long p;
if (n > 1)
p = n * mul(n - 1); /* 遞迴呼叫 */
else
p = 1UL; /* 基底條件 */
return p;
}
mul(5) → 5 * mul(4)mul(4) → 4 * mul(3)mul(3) → 3 * mul(2)mul(2) → 2 * mul(1)mul(1) 觸發基底條件,回傳 1| 項目 | 說明 |
|---|---|
| 回傳型別 | 採 unsigned long,可正確表示至 12! (479001600);13! 會溢位 32-bit。 |
| 基底條件 | n > 1 而非 n > 0,涵蓋 0! 與 1! 同為 1 的定義。 |
| 常數後綴 | 1UL 強制無號長整數,避免隱性轉型警告。 |
| 格式字串 | %lu 對應 unsigned long,原教材 %ld 為錯誤。 |
若將乘法移至參數傳遞:
unsigned long mul_tail(int n, unsigned long acc)
{
return (n <= 1) ? acc : mul_tail(n - 1, n * acc);
}
編譯器若支援尾端呼叫優化 (TCO),可將其轉為迴圈,消除堆疊增長。ANSI C 不強制要求 TCO,現代編譯器 (GCC/Clang/MSVC 在優化等級開啟時) 多支援此優化。
printf("mul(%d)\\n", n); 觀察呼叫深度。遞迴是程式設計的利器,掌握其「分解-解決-合併」的思維模式,對演算法設計與資料結構操作大有裨益。實務上請依據問題規模、效能需求與程式碼可讀性,在遞迴與迴圈間做權衡選擇。