經典 C 語言面試題:while(n++ < 10) printf("%d", n); 輸出什麼?直覺以為 0-10,實際輸出 1-10。根因在於 C 標準規定的「序列點」:while 判斷表達式結束即為序列點,**副作用(自增)必須在進入循環體前完成**
代碼與直覺對比
#include
#define TEN 10
int main() {
int n = 0;
while (n++ < TEN)
printf("%5d", n);
printf("\n");
return 0;
}
輸出結果
1 2 3 4 5 6 7 8 9 10
無 0,從 1 開始,到 10 結束。
標準解析:序列點與副作用
n++ < 10 是 while 的完整判斷表達式。
- C 標準規定:**完整表達式結束處是序列點**。
- 序列點之前,**所有副作用(如自增)必須完成**;序列點之後,副作用不得開始。
- 因此:
n++ 的副作用(n 變為 1)在 printf 執行前**已經生效**。
printf 使用的是已自增後的 n。
逐步執行還原
| 輪次 | 判斷前 n | n++ < 10 結果 | 副作用後 n | printf 輸出 |
| 1 | 0 | 0<10 真 | 1 | 1 |
| 2 | 1 | 1<10 真 | 2 | 2 |
| ... | ... | ... | ... | ... |
| 10 | 9 | 9<10 真 | 10 | 10 |
| 11 | 10 | 10<10 假 | 11 | (循環結束) |
對比:若副作用在循環體後
假設 C 允許「先用後增」延遲到循環體結束:
// 偽碼:錯誤理解
while (n < 10) {
printf("%d", n); // 輸出 0
n++; // 副作用延遲到這裡
}
// 實際輸出會是 0 1 2 ... 9
但標準**禁止**這種行為,編譯器必須確保副作用在序列點前完成。
前置自增對比
int n = 0;
while (++n < 10) // 前置自增
printf("%d", n);
// 輸出:1 2 3 4 5 6 7 8 9
// 判斷用增後值,n=10 時 10<10 偽,循環結束,不輸出 10
最佳實踐建議
- 避免在循環條件中使用副作用表達式:可讀性差,易出錯。
- 分離判斷與更新:
for (int n = 1; n <= 10; ++n) // 清晰、無歧義
printf("%d", n);
- 必須用 while 時:
int n = 0;
while (n < 10) {
++n;
printf("%d", n);
}
總結
while(n++ < 10) 輸出 1-10 而非 0-9,是因為 C 標準序列點規則強制副作用(自增)在進入循環體前完成。這不是編譯器 Bug,而是語言標準保障的確定性行為。理解序列點、副作用順序,是寫出無歧義 C 代碼的關鍵內功。
- 上一篇文章: C語言進程間通信:signal 信號處理與 kill 發送,父子進程同步實戰
- 下一篇文章: C語言進程間通信概述:三大核心問題與同步互斥基礎
Copyright ©
程式碼之家 All Rights Reserved