循環是程序控制流的核心構建塊。C 語言提供 for、while、do-while 三種循環結構,看似基礎,實則蘊含豐富的語義差異、編譯器優化機會與工程陷阱。本文系統梳理三種循環的適用場景、性能特性、進階技巧與最佳實踐。
| 特性 | for | while | do-while |
|---|---|---|---|
| 判斷時機 | 每次迭代前 | 每次迭代前 | 每次迭代**後** |
| 最少執行次數 | 0 | 0 | 1 |
| 典型適用場景 | 計數器、已知次數、複雜初始化/更新 | 條件驅動、未知次數、流處理 | 菜單交互、至少一次處理、解析器 |
| 作用域隔離 | C99 支持初始化聲明變量 | 無 | 無 |
| continue 行為 | 執行 update 表達式 | 直接跳到條件判斷 | 直接跳到條件判斷 |
for (int i = 0; i < n; i++) { ... } // C99: i 作用域限於循環
for (int i = 0, j = n - 1; i < j; i++, j--) { ... }
for (Node *p = head; p; p = p->next) { ... }
for (int *p = arr, *end = arr + n; p != end; ++p) { ... }
for (;;) { if (done) break; ... } // 比 while(1) 更符合習慣
for (int fd = open(...); fd >= 0; close(fd), fd = open(...)) { ... }
int c;
while ((c = getchar()) != EOF) { ... } // 返回值驅動
while (*src) *dst++ = *src++; // 經典 strcpy 核心
while (state != FINAL) {
state = transition(state, get_input());
}
do {
show_menu();
choice = get_choice();
execute(choice);
} while (choice != QUIT);
#define SAFE_FREE(p) do { free(p); (p) = NULL; } while (0)
// 使用:SAFE_FREE(ptr); 兼容 if/else 無大括號場景
do {
token = next_token();
parse(token);
} while (token != TOKEN_EOF);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (error) goto cleanup;
}
}
cleanup:
release_resources();
// 源碼
for (int i = 0; i < 100; i++) sum += a[i];
// -O2/-O3 可能展開為
for (int i = 0; i < 100; i += 4) {
sum += a[i]; sum += a[i+1]; sum += a[i+2]; sum += a[i+3];
}
// 源碼 for (int i = 0; i < n; i++) x = y * z + a[i]; // 優化後 int t = y * z; for (int i = 0; i < n; i++) x = t + a[i];
簡單循環、無副作用、連續內存訪問、計數已知 → 編譯器生成 SSE/AVX 指令。#pragma omp simd 或 __builtin_assume_aligned 輔助。
嵌套循環訪問二維數組時,調整順序利用緩存局部性:
// 差:列優先(步長大) for (j) for (i) a[i][j] = 0; // 優:行優先(連續) for (i) for (j) a[i][j] = 0;
for (size_t i = n-1; i >= 0; i--) // 無限循環!size_t 無符號
// 正確:
for (size_t i = n; i-- > 0;) { ... }
或用有符號:for (int i = n-1; i >= 0; i--)while (x = get()) 易誤寫為 ==,建議分行while (busy); 加分號或 {},防誤讀for (init; cond; update) [[unroll(4)]] 屬性提示展開因子do [[likely]] { ... } while (cond); 分支預測提示循環不只是重複執行,**選擇正確的循環類型、掌握控制流語義、理解編譯器優化觸發條件、規避類型陷阱**,才能寫出高性能、可維護、無 Bug 的迭代邏輯。實戰中:已知次數用 for、流處理用 while、交互/解析用 do-while、多層跳出用 goto、熱路徑引導向量化**。