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

C 語言經典題目解析:遞歸棧溢出與位運算副作用

     編輯:程式設計疑難解答

題目一:遞歸函數的輸出結果

#include <stdio.h>
#include <stdlib.h>

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

int main() {
    reverse(1);
    return 0;
}

選項: a) 1 2 3 4 5   b) 1 2 3 4   c) 編譯錯誤   d) 棧溢出

正確答案:d) 棧溢出

原因分析: 參數 i++ 是後置遞增,傳遞給遞歸調用的值仍是原值 i。因此 reverse(1) 會無限調用 reverse(1),永遠無法滿足 i > 5 的終止條件,導致無限遞歸最終棧溢出。若改為 ++i 或 i+1 則會正常輸出 1 到 5。

題目二:位運算與副作用的求值順序

#include <stdio.h>
int x = 0;
int f() { if (x == 0) return x + 1; else return x - 1; }
int g() { return x++; }

int main() {
    int i = (f() + g()) | g();  // 位或運算
    int j = g() | (f() + g());
    printf("i=%d, j=%d\n", i, j);
    return 0;
}

選項: a) i=1, j=1   b) i=0, j=0   c) i=1, j=未定義   d) i、j 均未定義

正確答案:c) i=1, j=未定義

詳細推導:

  • 表達式 i: C 標準規定 | 左右操作數有序列點,先算左邊 (f()+g())。
    f() 先執行:x=0 → 返回 1,x 仍為 0。
    g() 再執行:返回 0,x 變為 1。
    左邊值 = 1+0 = 1。
    右邊 g():返回 1,x 變為 2。
    1 | 1 = 1 → i = 1。
  • 表達式 j: 同樣先算左邊 g():返回 2,x 變為 3。
    右邊 (f()+g()) 中,f() 與 g() 的求值順序未指定(無序列點),若先 f() 則 x=3 返回 2;若先 g() 則返回 3 且 x=4,導致 f() 返回 3。最終結果不確定 → j 未定義。

核心知識點

  1. 後置遞增 i++ 在遞歸/函數參數中易導致邏輯錯誤。
  2. 位運算 |、&、^ 有序列點,但函數參數求值順序未規定,包含副作用的函數調用會產生未定義行為。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved