首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C語言遞歸陷阱:i++ 與 (i++, i) 導致棧溢出的根本原因

     編輯:程式設計疑難解答

兩段代碼對比

代碼一:棧溢出版

void reverse(int i) {
    if (i > 5) exit(0);
    printf("%d\n", i);
    return reverse(i++);  // 後置++
}

代碼二:正常退出版

void reverse(int i) {
    if (i > 5) return;
    printf("%d ", i);
    return reverse((i++, i)); // 逗號表達式
}

根本原因深度解析

後置++ 的欺騙性

i++ 的值是遞增前的值,副作用是i變為i+1。但在函數參數傳遞時:

  1. 計算參數表達式值:i++ 取值為當前i
  2. 調用函數:reverse(當前i)
  3. 參數求值完成後,i才真正+1

結果:每次遞歸傳入的都是初始值1,無限遞歸 → 棧溢出。

逗號表達式的威力

(i++, i) 是逗號表達式,值為最後一個子表達式的值:

  1. 執行 i++,i 變為 i+1
  2. 取 i 的新值作為整個表達式的值
  3. 傳入 reverse(新i)

結果:參數真正遞增,滿足終止條件正常退出。

等價改寫驗證

// 代碼一等價於
void reverse(int i) {
    if (i > 5) exit(0);
    printf("%d\n", i);
    int temp = i;
    i = i + 1;      // 副作用發生在調用後
    return reverse(temp); // 永遠傳遞初始值
}

// 代碼二等價於
void reverse(int i) {
    if (i > 5) return;
    printf("%d ", i);
    i = i + 1;      // 先遞增
    return reverse(i);    // 傳遞新值
}

避坑口訣

  • 遞歸參數嚴禁使用後置++/--
  • 需先修改再傳遞時,用前置++或逗號表達式
  • 最清晰寫法:return reverse(i + 1); 無副作用,語義明確
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved