問題:交換兩個變數 a、b 的值
方法一:臨時變數(最通用、最安全)
int a, b, t;
scanf("%d %d", &a, &b);
t = a; a = b; b = t;
printf("%d %d\n", a, b);
- ✅ 適用所有型別(整數、浮點、結構體、指標)
- ✅ 無溢位風險、無副作用
- ✅ 編譯器優化極佳(常優化為寄存器交換)
- ⚠️ 需額外儲存空間(可忽略不計)
方法二:算術運算(無臨時變數,整數適用)
int a, b;
scanf("%d %d", &a, &b);
a = a + b; // a = a₀ + b₀
b = a - b; // b = (a₀ + b₀) - b₀ = a₀
a = a - b; // a = (a₀ + b₀) - a₀ = b₀
printf("%d %d\n", a, b);
- ⚠️ 溢位風險:
a + b 可能超出型別範圍(有號整數溢位 = UB)
- ⚠️ 僅適用數值型別,不適用指標/結構體
- ⚠️ 現代編譯器優化下不比臨時變數快
方法三:位元 XOR 交換(無臨時變數、無溢位)
int a, b;
scanf("%d %d", &a, &b);
a ^= b; // a = a₀ ⊕ b₀
b ^= a; // b = b₀ ⊕ (a₀ ⊕ b₀) = a₀
a ^= b; // a = (a₀ ⊕ b₀) ⊕ a₀ = b₀
printf("%d %d\n", a, b);
- ✅ 無溢位、位級操作
- ⚠️ 同一變數交換失效:
swap(x, x) 導致歸零
- ⚠️ 僅適用整數型別
- ⚠️ 現代 CPU 流水線下較慢(相依鏈長)
方法四:直接輸出交換(僅顯示需求)
int a, b;
scanf("%d %d", &a, &b);
printf("%d %d\n", b, a); // 不修改變數,僅交換輸出順序
- ✅ 最簡潔、零開銷
- ⚠️ 僅適用「只需輸出交換結果」的場景
- ⚠️ 變數本身值未變,後續使用仍為原值
方法五:堆疊/汇編視角(教學用)
/* 概念示意 */
push a
push b
pop a // a 獲取原 b
pop b // b 獲取原 a
- 函數呼叫慣例中實際發生:參數入棧、返回值出棧
- 內聯汇編可直接操作:
xchg 指令 (x86)
綜合對比表
| 方法 | 適用型別 | 溢位風險 | 同變數安全 | 可讀性 | 推薦度 |
| 臨時變數 | 所有 | 無 | ✅ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 算術加減 | 數值 | 高 | ✅ | ⭐⭐⭐ | ⭐⭐ |
| XOR 位運算 | 整數 | 無 | ❌ | ⭐⭐ | ⭐⭐ |
| 輸出交換 | 所有 | 無 | N/A | ⭐⭐⭐⭐ | 情境專用 |
| std::swap / 內建 | 所有 | 無 | ✅ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ (C++) |
現代最佳實踐
- C:使用臨時變數,或封裝為
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
- C++:
std::swap(a, b)(泛型、移動語意、ADL、特化優化)
- 編譯器優化:
-O2 下臨時變數交換常優化為寄存器 xchg 或重命名,零記憶體存取
- 避免花招:XOR/算術交換在現代架構上不比臨時變數快,且引入風險
經典面試陷阱題
void swap(int *a, int *b) {
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
int x = 5;
swap(&x, &x); // x 變為 0!生產代碼禁用 XOR swap