遞迴是程式設計中極具威力卻常讓初學者困惑的技巧。本文透過一個「將整數按逆序存入字元陣列」的經典範例(如 483 → "384"),逐步拆解遞迴的呼叫堆疊、參數傳遞與返回流程,幫助建立正確的遞迴心智模型。
#include <stdio.h>
void convert(char* a, int n) {
int i;
if ((i = n / 10) != 0)
convert(a + 1, i); // 遞迴呼叫:指標後移,處理高位
*a = n % 10 + '0'; // 存入當前最低位
printf("%c ", *a); // 除錯輸出
}
int main() {
int number;
char str[10] = " ";
scanf("%d", &number);
convert(str, number);
puts(str);
return 0;
}
輸入 483,輸出:
3 8 4 384
main()
└─ convert(str, 483) // 第 1 層:n=483, a 指向 str[0]
├─ i = 48 ≠ 0
└─ convert(str+1, 48) // 第 2 層:n=48, a 指向 str[1]
├─ i = 4 ≠ 0
└─ convert(str+2, 4) // 第 3 層:n=4, a 指向 str[2]
├─ i = 0 → 不遞迴
├─ *a = 4%10+'0' = '4' ← 最先執行賦值
└─ printf('4')
├─ 返回第 2 層
├─ *a = 48%10+'0' = '8' ← 次執行
└─ printf('8')
├─ 返回第 1 層
├─ *a = 483%10+'0' = '3' ← 最後執行
└─ printf('3')
├─ puts(str) → 輸出 "384"
a+1 讓每層寫入不同位置,自然形成逆序n/10 == 0 時停止遞迴,直接處理最高位初始: str = [ , , , , , , , , , ] 第3層: str = [ , , '4', , , , , , , ] ← a+2 第2層: str = [ , '8', '4', , , , , , , ] ← a+1 第1層: str = ['3', '8', '4', , , , , , , ] ← a
註解中的 convert((a++, a--), i) 使用逗號運算子達成相同效果,但可讀性極差,不建議實務使用。標準迴圈版本:
void convert_iter(char* a, int n) {
char* p = a;
// 先算出位數
int len = 0, temp = n;
do { temp /= 10; len++; } while (temp);
p += len - 1;
// 從低位寫入高位
do {
*p-- = n % 10 + '0';
n /= 10;
} while (n);
}
| 要素 | 本範例體現 |
|---|---|
| 基底案例 | n/10 == 0 直接處理最高位 |
| 縮小問題 | n/10 減少位數,a+1 移動寫入位置 |
| 合併結果 | 各層依序寫入字元陣列,自動組合完整字串 |
這個範例完美展示了遞迴「向下分解、向上合併」的核心特徵:遞迴呼叫負責分解問題(處理高位),返回過程負責合併結果(寫入低位)。理解呼叫堆疊的記憶體狀態演變,是掌握遞迴的關鍵。實務上,尾遞迴優化或迴圈重寫可避免堆疊溢位風險。