C 語言擁有豐富的運算子集合,按功能可分為:算術、關係、邏輯、位元、賦值、條件、逗號、sizeof、取址、間接存取、下標、函式呼叫、結構成員存取等。本文聚焦**易混淆、高頻考點、實戰陷阱**的核心子集。
expr1, expr2, ..., exprN
int a=1, b=2, c;
c = a + b + 3; // 普通逗號分隔宣告,非運算子
c = (a++, a+=b, a-b); // 逗號運算子:a=2 → a=4 → 值=2
printf("%d %d %d", a, b, c); // 4 2 2
括號**必不可少**:`c = a++, a+=b, a-b;` 等價於 `(c=a++), a+=b, a-b;` → `c=1`。
char x='m', y='n';
int n = x < y; // 1 ('m'=109 < 'n'=110)
n = x == y - 1; // 1 (109 == 110-1)
n = ('y' != 'Y') + (5 < 3) + (y - x == 1); // 1 + 0 + 1 = 2
**關鍵洞察**:關係表達式結果是 `int` (0/1),可直接參與加減乘除、陣列索引等。
int a=b=c=10;
a = b == c; // a = (b==c) → a=1,非 a=b 再 ==c
a = (b + (c++ > 2)); // c++>2 為 1 → a = 10+1 = 11
a = b > c * 100; // * 優先於 > → c*100=1100 → b>1100 為 0
| 運算子 | 名稱 | 短路規則 | 結果型別 |
|---|---|---|---|
| `!` | 邏輯非 | 單目,無短路 | `int` (0/1) |
| `&&` | 邏輯與 | 左側為 0 → 右側**不求值** | `int` (0/1) |
| `||` | 邏輯或 | 左側非 0 → 右側**不求值** | `int` (0/1) |
// && 短路:左側 0 即停
int m, k;
k = (m=0) && (m=1); printf("m=%d k=%d\n", m, k); // m=0 k=0 (右側未執行)
k = (m=1) && (m=0); printf("m=%d k=%d\n", m, k); // m=0 k=0 (右側執行,m變0)
k = (m=2) && (m=1) && (m=0); // m=0 k=0
// || 短路:左側非 0 即停
k = (m=0) || (m=1); // m=1 k=1
k = (m=1) || (m=0); // m=1 k=1 (右側未執行)
// 後綴遞增配合短路
m=0, k=0; int n = k++ && m++; // k=0→假,短路,m 不增 → n=0, k=1, m=0
m=0, k=0; n = m++ && k++; // m=0→假,短路,k 不增 → n=0, m=1, k=0
k = (m=0) || (m=1) && (m=2); // 解析為 (m=0) || ((m=1)&&(m=2)) → m=2, k=1
k = (m=2) && (m=1) || (m=0); // ((m=2)&&(m=1)) || (m=0) → m=1, k=1
**口訣**:「與綁定緊,或綁定鬆」,不確定時**加括號**。
expr1 ? expr2 : expr3
char ch; scanf("%c", &ch);
ch = (ch >= 'A' && ch <= 'Z') ? (ch + 'a' - 'A') : ch;
printf("%c\n", ch);
int score; char grade;
grade = score >= 90 ? 'A' :
score >= 80 ? 'B' :
score >= 70 ? 'C' :
score >= 60 ? 'D' : 'F';
// 等價於
grade = score >= 90 ? 'A' : (score >= 80 ? 'B' : (score >= 70 ? 'C' : (score >= 60 ? 'D' : 'F')));
sizeof(int) // 型別名需加括號
sizeof variable // 變數名可不加括號
sizeof expression // 表達式可不加括號,**不求值表達式**
int a[10];
int *p = a;
printf("%zu %zu", sizeof(a), sizeof(p)); // 40 8 (假設 32-bit int, 64-bit 指標)
int x, y=1, z;
x = ((9+6)%5 >= 9%5 + 6%5) ? 1 : 0; // (0 >= 4+1=5) → 0
y += z = x + 3; // z=3, y=1+3=4
x=y=z=1;
--x && ++y || z++; // --x=0→假,短路 ||,++y 不執行,z++ 執行
// x=0, y=1, z=2
1. 後綴: () [] -> . ++ --
2. 前綴: ++ -- + - ! ~ * & sizeof (type)
3. 乘除餘: * / %
4. 加減: + -
5. 位移: << >>
6. 關係: < <= > >=
7. 等值: == !=
8. 位元 AND: &
9. 位元 XOR: ^
10. 位元 OR: |
11. 邏輯 AND: &&
12. 邏輯 OR: ||
13. 條件: ?:
14. 賦值: = += -= *= /= %= &= ^= |= <<= >>=
15. 逗號: ,
**同優先級**依**結合性**決定順序:多為**左結合**,賦值/條件/單目為**右結合**。
int c = 0;
c + --c; // c 求值順序未定:可能 0+(-1)=-1 或 -1+(-1)=-2
f() + g() + h(); // 三函式呼叫順序未定,若有副作用結果不可預期
解法:引入暫存變數強制順序:
int t1 = f(), t2 = g(), t3 = h();
int sum = t1 + t2 + t3;
int *p, *p1;
p + 2; // 位址 + 2*sizeof(int)
p - 2; // 位址 - 2*sizeof(int)
p2 - p1; // 元素個數差 = (位址差) / sizeof(int)
**標準保證**:指向陣列元素的指標,可與**最後一個元素之後**的位址比較(`<`、`==`),**不可**與第一個元素之前比較。
運算子是 C 語言表達計算意圖的詞彙。精通優先級、結合性、短路求值、求值順序未定義四大核心概念,能讓你寫出既正確又高效的表達式。實戰中:複雜表達式拆分成多語句、不確定優先級加括號、副作用運算元絕不共用,是避開 90% 運算子陷阱的鐵律。