1 C 語言運算子優先順序與結合性總表
寫程式時,「看起來長怎樣」並不代表「會照那個順序算」!下表是 C 語言標準優先順序(數字 1 優先權最高,先算;數字 15 最低,最後算):
| 優先權 | 運算子類別 | 代表符號 | 結合方向 (Associativity) |
|---|---|---|---|
| 1 (最高) | 括號、陣列下標、結構成員 | () [] . -> |
由左至右 (Left-to-Right) |
| 2 | 一元運算子、前置遞增減、轉型 | ! ~ ++ -- + - * & (type) sizeof |
由右至左 (Right-to-Left) |
| 3 | 算術乘、除、取餘數 | * / % |
由左至右 |
| 4 | 算術加、減 | + - |
由左至右 |
| 5 | 位元左移、右移 | << >> |
由左至右 |
| 6 | 關係比較大小 | < <= > >= |
由左至右 |
| 7 | 相等比較 | == != |
由左至右 |
| 8 | 位元 AND | & |
由左至右 |
| 9 | 位元 XOR | ^ |
由左至右 |
| 10 | 位元 OR | | |
由左至右 |
| 11 | 邏輯 AND | && |
由左至右 |
| 12 | 邏輯 OR | || |
由左至右 |
| 13 | 條件運算子(三元) | ? : |
由右至左 (Right-to-Left) |
| 14 | 賦值運算子 | = += -= *= /= %= <<= >>= &= ^= |= |
由右至左 (Right-to-Left) |
| 15 (最低) | 逗號運算子 | , |
由左至右 |
2 統測四大優先序「奪命連環陷阱」(歷屆考題高頻重災區)
統測 114 年專二 Q40 經典考題:a ^ b == x
• ❌ 直覺誤以為是 (a ^ b) == x。
• ✅ 真實編譯解析為 a ^ (b == x)! 因為 ==(第 7 級)優先於 ^(第 9 級)!
統測 112 年專二 Q44 經典考題:Num1 << Num3 - 1
• ❌ 直覺誤以為先算 Num1 << Num3 再減 1。
• ✅ 真實編譯解析為 Num1 << (Num3 - 1)! 因為減法 -(第 4 級)優先於位移 <<(第 5 級)!
統測 115 年專二 Q44 經典考題:(int) total * 1.1
• ❌ 直覺誤以為是先把乘法算完再轉整數 (int)(total * 1.1)。
• ✅ 真實編譯解析為 ((int)total) * 1.1! 因為轉型 (type)(第 2 級)優先於乘法 *(第 3 級)!
x & y && a == b 的真實執行順序為:(x & y) && (a == b)。
3 前置遞增 ++a vs 後置遞增 a++ 深度拆解
遞增(++)與遞減(--)運算子看似簡單,但放進算式或陣列索引時,前後位置代表截然不同的求值時機:
| 語法 | 名稱 | 執行邏輯(口訣) | 範例程式碼 (初始 a = 5) | 運算結果 |
|---|---|---|---|---|
++a |
前置遞增 (Pre-increment) | 「先加 1,再拿新值去算」 | int b = ++a * 2; |
a 先變 6,b = 6 × 2 = 12 |
a++ |
後置遞增 (Post-increment) | 「先拿舊值去算,整句結束才加 1」 | int b = a++ * 2; |
先用 a 的舊值 5 算 b = 5 × 2 = 10;之後 a 才變成 6 |
#include <stdio.h>
int main(void) {
int a = 1, b = 3, c = 5, d = 7;
// x = a++/b + c*++d;
// 步驟 1: a++ 是後置遞增,在算式中使用舊值 1 (算完後 a 變 2)
// 步驟 2: ++d 是前置遞增,d 先加 1 變成 8,拿 8 參與乘法
// 步驟 3: a/b 即 1/3,整數除法得 0
// 步驟 4: c*++d 即 5*8 = 40
// 步驟 5: 0 + 40 = 40
int x = a++ / b + c * ++d;
printf("x = %d, a = %d, d = %d\n", x, a, d);
return 0;
}
4 位元運算子全圖解(&, |, ^, ~, <<, >>)
位元運算是直接對二進位中的每一個 bit(0 與 1)單獨做邏輯運算:
| 運算子 | 名稱 | 運算真值規則 (Truth Table) | 範例 (a = 10即 1010₂, b = 5即 0101₂) | 常見核心應用 |
|---|---|---|---|---|
& |
位元 AND | 1 & 1 = 1,其餘全為 0 | 1010 & 0101 = 0000 (0) |
位元遮罩(Masking):提取特定位元、將特定位元清零。 |
| |
位元 OR | 0 | 0 = 0,其餘全為 1 | 1010 | 0101 = 1111 (15) |
置 1(Set Bit):將特定位元強制設為 1。 |
^ |
位元 XOR | 相異為 1,相同為 0 | 1001 ^ 0111 = 1110 (14)(統測 111 年 Q40) |
位元反轉、兩數無暫存交換、奇偶校驗。 |
~ |
位元 NOT | 0 變 1、1 變 0(一補數反相) | ~00001010 = 11110101( ~x = -x - 1) |
全位元反轉。 |
<< |
左移運算子 | 所有位元向左移 $n$ 格,右邊補 0 | 10 << 2 = 40 (相當於 10 × 2² = 40) |
快速乘以 $2^n$。 |
>> |
右移運算子 | 所有位元向右移 $n$ 格,左邊補符號/0 | 200 >> 1 = 100 (相當於 200 ÷ 2¹ = 100) |
快速除以 $2^n$(無條件捨去)。 |
#include <stdio.h>
int main(void) {
int a = 9; // 二進位 1001
int b = 7; // 二進位 0111
// 1001 ^ 0111 = 1110 (十進位 14)
printf("a ^ b = %d\n", a ^ b);
// 位移快速乘除:
int x = 10;
printf("10 << 2 = %d (10 * 4)\n", x << 2); // 40
printf("40 >> 1 = %d (40 / 2)\n", 40 >> 1); // 20
return 0;
}
10 << 2 = 40 (10 * 4)
40 >> 1 = 20 (40 / 2)
5 位元運算(&、|)vs 邏輯運算(&&、||)與短路求值
統測超愛考 & 與 && 的區別(112 年專二 Q45):
| 比較項目 | 位元 AND (&) |
邏輯 AND (&&) |
|---|---|---|
| 運算對象 | 逐個 bit(二進位 0/1)計算。 | 看整個運算式的「真(非 0)」或「假(0)」。 |
| 回傳結果 | 算出位元運算後的整數數值。 | 真假值:1 (true) 或 0 (false)。 |
| 短路求值 (Short-circuit) | ❌ 兩邊必定都完整計算。 | ✅ 具備短路特性:左邊為 0 (假),右邊直接跳過不執行! |
#include <stdio.h>
int main(void) {
int a = 0x0a; // 0x0A = 十進位 10 = 二進位 1010
int b = 0x05; // 0x05 = 十進位 5 = 二進位 0101
// 位元 AND: 1010 & 0101 = 0000 = 0 (在 if 條件中為「假」)
if (a & b) {
printf("a&b=%d\n", a & b);
} else {
// 邏輯 AND: a(10!=0為真) && b(5!=0為真) => 結果為 1 (真)
printf("a&&b=%d\n", a && b); // 印出 a&&b=1
}
return 0;
}
6 條件運算子(三元運算子 ? :)
三元運算子是 C 語言中唯一需要三個運算元的運算子,格式為:
條件式 ? 條件為真時的值 : 條件為假時的值
#include <stdio.h>
int main(void) {
unsigned char b = 127; // 01111111
unsigned char c = 128; // 10000000
// b | c = 01111111 | 10000000 = 11111111 = 255
// 條件判斷 (b | c) == 0 => 255 == 0 (條件為假!)
// 因此選擇冒號後方的表達式: b & c
// b & c = 01111111 & 10000000 = 00000000 = 0
int y = (b | c) == 0 ? b ^ c : b & c;
printf("y = %d\n", y); // 輸出 0
return 0;
}
7 餘數運算子 (%) 與遮罩實務應用
餘數運算子 %(Modulo)只能用於整數型態。在統測中常與位元遮罩結合,用來判斷固定奇偶數(如統測 113 年 Q41):
• 任何整數的二進位,最低位元(bit 0)決定奇偶(0 為偶數、1 為奇數)。
• (X & 2):只取 bit 1(權值為 2),其結果必定只有 0 或 2(皆為偶數)!
• 2 % 5 = 2(餘數 2 為偶數)。
• 偶數 + 偶數 = 恆為偶數(與 X 之數值完全無關!)。
8 111~115 歷屆統測真題全選項深度剖析(共 10 題)
以下收錄統測專業科目(二)近年全部 10 題運算子與優先序真題。每題均提供高解析度原始考題掃描圖、互動選項按鈕與所有選項逐項深入解析:
#include <stdio.h>
int main()
{
int a=9, b=7;
printf("%d", a^b);
return 0;
}
🔍 四個選項逐項深度剖析
a = 9 轉為二進位:1001₂。2.
b = 7 轉為二進位:0111₂。3. 逐位元執行 XOR(相異為 1,相同為 0):
1 0 0 1^ 0 1 1 1---------1 1 1 0₂ = 8 + 4 + 2 + 0 = 十進位 14,故選 (C)。
^ 當作位元 AND(1001 & 0111 = 0001 = 1)會誤選 (A)。• 若誤把
^ 當作減法(9 - 7 = 2)會誤選 (B)。• 若誤把
^ 當作位元 OR(1001 | 0111 = 1111 = 15)會誤選 (D)。
🔍 四個選項逐項深度剖析
1!=3 為真 (1),取 ! 變成假 (0);1==3 為假 (0);0 || 0 結果為 0 (false)。1!=3 為真 (1);1==3 為假 (0),!(0) = 1,!(1) = 0;1 && 0 結果為 0 (false)。1<3 為真 (1),取 ! 變成假 (0);1>=3 為假 (0);0 || 0 結果為 0 (false)。1<3 為真 (1);1>=3 為假 (0),取 ! 變成真 (1);1 && 1 結果為 1 (true)!故選 (D)。int Num1 = 10, Num2 = 5;
int Num3 = 3;
Num1 = Num1 << Num3 - 1;
Num2 = Num2 * Num1 >> 1;
🔍 四個選項逐項深度剖析
- 的優先序高於位移 <<,故 Num1 << Num3 - 1 等同於 10 << (3 - 1) = 10 << 2 = 10 × 2² = 40。2. 計算 Num2:乘法
* 的優先序高於位移 >>,故 Num2 * Num1 >> 1 等同於 (5 * 40) >> 1 = 200 >> 1 = 200 ÷ 2¹ = 100。故 Num1=40、Num2=100,選 (D)。
(10 << 3) - 1 = 80 - 1 = 79)會誤選 (A) 或 (B)。• 若計算 Num2 忘記右移除以 2(維持 200)會誤選 (C)。
& 與 && 的不同,下列何者為程式執行結果?
#include <stdio.h>
int main() {
int a = 0x0a;
int b = 0x05;
if(a & b)
printf("a&b=%d\n", a&b);
else
printf("a&&b=%d\n", a&&b);
return 0;
}
🔍 四個選項逐項深度剖析
a = 0x0a = 1010₂,b = 0x05 = 0101₂。2.
a & b = 1010 & 0101 = 0000 = 0。3.
if(0) 條件判定為假,因此跳過 if 區塊,執行 else 區塊!4. 在 else 中,
a && b 為邏輯 AND:a(10!=0為真) && b(5!=0為真) $ o$ 結果為 1 (true)。5. 故輸出 a&&b=1,選 (A)。
🔍 四個選項逐項深度剖析
% 優先序高於 +,故先算 2 % 5 = 2(偶數)。2.
((A + 124) & 2) 是對二進位第 1 個 bit(權值為 2)做遮罩,結果必定只有 0 或 2(皆為偶數)。3.
(0 或 2) + 2 的結果必定為 2 或 4,恆為偶數,且完全不受 A 值影響!故選 (D)。
| 0x4 只保證 bit 2 為 1,若左側為奇數(bit 0 為 1),OR 完依然是奇數。• (B)
& 0x1B(00011011₂),bit 0 為 1,奇偶性隨 A 變化。• (C)
(A - 15) / 2 + 6 的奇偶性隨 A 變化。
if((x*x)%2&&a^b==x)
x=1;
else
x=0;
🔍 四個選項逐項深度剖析
==(第 7 級)高於 ^(第 9 級),^ 又高於 &&(第 11 級)。2. 因此
a^b==x 實際上被解析為 a ^ (b == x),而不是 (a ^ b) == x!3. 對照三元運算子
條件 ? 1 : 0,只有 (C) 正確寫出 a ^ (b == x),故選 (C)。
a^b==x 加上括號 (a^b)==x,完全落入出題老師設計的優先序陷阱!
int a=1, b=3, c=5, d=7, x=0;
x = a++/b+c*++d;
printf("%d", x);
🔍 逐步運算拆解
* / 優先於 加法 +。2.
a++ / b:a++ 是後置遞增,在算式中使用舊值 1 $ o$ 1 / 3 = 0(整數除法小數捨去)。3.
c * ++d:++d 是前置遞增,d 先從 7 加 1 變成 8 $ o$ 5 * 8 = 40。4.
x = 0 + 40 = 40,選 (D)。
#include <iostream>
int main(){
unsigned int a=128, b=255, c;
c=(~a<<2^b|a)&0xff;
std::cout<<std::hex<<c;
}
🔍 運算子優先序逐步推導
~(第 2 級)> <<(第 5 級)> ^(第 9 級)> |(第 10 級)。2. 故
(~a<<2^b|a) 實際上為 ((((~a) << 2) ^ b) | a)。3.
a = 128 = 0x80 (00000000...10000000₂)。4.
~a 最低 Byte 為 0x7F (01111111₂)。5.
(~a) << 2 最低 Byte 為 0x7F << 2 = 0xFC (11111100₂)。6.
0xFC ^ b (b=0xFF):11111100 ^ 11111111 = 00000011₂ = 0x03。7.
0x03 | a (a=0x80):00000011 | 10000000 = 10000011₂ = 0x83。8. 最後
& 0xff 取最低 Byte 即為 0x83。以十六進位印出 83,選 (B)。
unsigned char b = 127, c = 128, y = 255;
y = (b|c)==0?b^c:b&c;
printf("y=%d", y);
🔍 四個選項逐項深度剖析
b = 127 = 01111111₂,c = 128 = 10000000₂。2.
b | c = 01111111 | 10000000 = 11111111₂ = 255。3. 條件判斷
(b | c) == 0 即 255 == 0(結果為 假)。4. 三元運算子
條件 ? 算式1 : 算式2 選擇冒號後的 b & c。5.
b & c = 01111111 & 10000000 = 00000000₂ = 0。6. 故
y = 0,輸出 y=0,選 (A)。
total = g_n * 30 + r_n * 20;
if(s_flag == 's')
total = (int) total * 1.1;
if(buy == 'y')
total = total + 2;
printf("%d,%d,%c,%c,%d", r_n, g_n, s_flag, buy, total);
🔍 四個選項逐項深度剖析
total = g_n * 30 + r_n * 20 = 3 * 30 + 2 * 20 = 90 + 40 = 130。2.
s_flag == 's':因為 s_flag = 'g',條件不成立,跳過打折計算。3.
buy == 'y':因為 buy = 'n',條件不成立,跳過加 2 元計算。4.
total 保持原值 130,printf 輸出 2,3,g,n,130,選 (B)。
9 高職段考與模擬精選實戰題(5 題全選項解析)
透過以下 5 題精選模擬試題,全面檢驗你對運算子優先序、短路求值與位元運算的掌握度:
int a = 0, b = 5;,執行 if (a++ && ++b) { a += 10; } 後,變數 a 與 b 的值分別為何?
🔍 四個選項逐項深度剖析
a++ 是後置遞增,在 && 判斷中使用 a 的舊值 0(假)。之後 a 遞增變成 1。2. 短路求值特性:由於
&& 左側已確定為假 (0),編譯器直接跳過右側 ++b 的執行!故 b 維持原值 5 不變!3. if 條件為假,不會進入
a += 10;。故最終 a = 1, b = 5,選 (B)。
int a = 2, b = 3, c = 4;,執行 a += b *= c + 1; 後,變數 a 與 b 的值為何?
🔍 四個選項逐項深度剖析
+ 優先序高於複合賦值,先算 c + 1 = 4 + 1 = 5。2. 賦值運算子
+= 與 *= 為由右至左結合:先算右側 b *= 5 $ o$ b = 3 * 5 = 15。3. 再算左側
a += 15 $ o$ a = 2 + 15 = 17。故 a = 17, b = 15,選 (C)。
int x = 12, y = 25;,連續執行 x ^= y; y ^= x; x ^= y; 後,x 與 y 的值分別為何?
🔍 四個選項逐項深度剖析
1.
x = x ^ y2.
y = y ^ x = y ^ (x ^ y) = x(此時 y 拿到 x 的原值 12)3.
x = x ^ y = (x ^ y) ^ x = y(此時 x 拿到 y 的原值 25)兩數成功交換,故 x = 25, y = 12,選 (A)。
num 的第 3 個位元(bit 3,權值為 8)是否為 1,下列哪一個運算式最適當?
🔍 四個選項逐項深度剖析
num 向右移 3 位(num >> 3),會將原本在第 3 位的 bit 移到最右側最低位(bit 0);再與 1 進行位元 AND(& 1),即可精準提取出該位元的值(0 或 1)。故選 (A)。
int score = 85; char grade = score >= 90 ? 'A' : score >= 80 ? 'B' : 'C'; 後,grade 的值為何?
🔍 四個選項逐項深度剖析
1.
score >= 90(85 ≥ 90 假),選擇冒號右邊的表達式。2. 進入右邊三元運算:
score >= 80(85 ≥ 80 真),選擇問號後的 'B'。故
grade = 'B',選 (B)。
10 考前衝刺 10 秒速記口訣 & 核心知識檢核清單
== 優先於 ^ & |;+ - 優先於 << >>;(int) 優先於 * /。
++a 先加後用;a++ 先用後加。
a ^ b 相異為 1,相同為 0;a ^ a = 0,a ^ 0 = a。
<< n 乘以 2n;>> n 除以 2n。
0 && (任何式) 右邊不執行;1 || (任何式) 右邊不執行。
& 算二進位數值;&& 判斷真假 (1/0)。