在C語言中,操作符是構建表達式的基礎,掌握各類操作符的用法、優先級及特性,對寫出高效且正確的代碼至關重要。本文將系統梳理C語言操作符的核心知識點,包含實例代碼與詳細解析,助你徹底搞懂操作符。
1. 操作符的分類
C語言操作符可按功能分為以下幾類,清晰的分類有助于理解其特性:
類別 | 操作符 |
---|---|
算術操作符 | + 、- 、* 、/ 、% |
移位操作符 | << 、>> |
位操作符 | & 、| 、^ 、~ |
賦值操作符 | = 、+= 、-= 、*= 、/= 、%= 、<<= 、>>= 、&= 、|= 、^= |
單目操作符 | ! 、++ 、-- 、& 、* 、+ 、- 、~ 、sizeof 、(類型)(強制類型轉換) |
關系操作符 | > 、>= 、< 、<= 、== 、!= |
邏輯操作符 | && 、|| |
條件操作符 | ? : |
逗號表達式 | , |
下標引用 | [] |
函數調用 | () |
結構成員訪問操作符 | . 、-> |
2. 二進制與進制轉換
計算機底層使用二進制存儲數據,掌握進制轉換是理解位操作的基礎。
2.1 二進制與十進制轉換
-
二進制轉十進制:按權重展開求和(權重為20,21,22,...2^0, 2^1, 2^2,...20,21,22,...,從右向左)。
例:二進制1101
轉十進制:
1×23+1×22+0×21+1×20=8+4+0+1=131×2^3 + 1×2^2 + 0×2^1 + 1×2^0 = 8 + 4 + 0 + 1 = 131×23+1×22+0×21+1×20=8+4+0+1=13 -
十進制轉二進制:除2取余,余數倒序排列。
例:十進制125
轉二進制:
125 ÷ 2 = 62 余1
62 ÷ 2 = 31 余0
31 ÷ 2 = 15 余1
15 ÷ 2 = 7 余1
7 ÷ 2 = 3 余1
3 ÷ 2 = 1 余1
1 ÷ 2 = 0 余1
結果:1111101
2.2 二進制與八/十六進制轉換
-
二進制轉八進制:從右向左每3位一組,不足補0,每組對應1個八進制數(0-7)。
例:二進制01101011
→ 分組01 101 011
→ 轉換為八進制153
(前綴0
表示八進制)。 -
二進制轉十六進制:從右向左每4位一組,不足補0,每組對應1個十六進制數(0-9, a-f)。
例:二進制01101011
→ 分組0110 1011
→ 轉換為十六進制0x6b
(前綴0x
表示十六進制)。
3. 原碼、反碼、補碼
整數在內存中以補碼存儲,原因是:統一符號位與數值位處理,簡化加法運算(CPU僅需加法器)。
-
原碼:直接表示符號位(0正1負)和數值位。
例:int a = 3
→ 原碼00000000 00000000 00000000 00000011
int b = -3
→ 原碼10000000 00000000 00000000 00000011
-
反碼:原碼符號位不變,數值位取反。
例:-3
的反碼11111111 11111111 11111111 11111100
-
補碼:反碼+1(負數補碼);正數原碼=反碼=補碼。
例:-3
的補碼11111111 11111111 11111111 11111101
4. 移位操作符
移位操作符僅作用于整數,分為左移和右移。
4.1 左移操作符 <<
- 規則:左邊丟棄,右邊補0。
- 示例:
#include <stdio.h>
int main() {int num = 10; // 二進制:00000000 00000000 00000000 00001010int n = num << 1; // 左移1位:00000000 00000000 00000000 00010100 → 20printf("n = %d\n", n); // 輸出:20printf("num = %d\n", num); // 輸出:10(原變量不變)return 0;
}
4.2 右移操作符 >>
- 邏輯右移:左邊補0,右邊丟棄(無符號數)。
- 算術右移:左邊補符號位,右邊丟棄(有符號數,主流編譯器采用)。
示例(算術右移):
#include <stdio.h>
int main() {int num = -1; // 補碼:11111111 11111111 11111111 11111111int n = num >> 1; // 算術右移1位:11111111 11111111 11111111 11111111 → 仍為-1printf("n = %d\n", n); // 輸出:-1return 0;
}
?? 注意:禁止移動負數位(如num >> -1
,行為未定義)。
5. 位操作符
位操作符直接對二進制位進行操作,操作數為整數。
操作符 | 功能 | 示例(二進制) |
---|---|---|
`&` | 按位與(同1則1) | 1010 & 0111 = 0010 |
`|` | 按位或(有1則1) | 1010 | 0111 = 1111 |
`^` | 按位異或(不同則1) | 1010 ^ 0111 = 1101 |
`~` | 按位取反(0變1,1變0) | ~1010 = 0101(假設4位) |
經典案例
- 不創建臨時變量交換兩數:
#include <stdio.h>
int main() {int a = 10, b = 20;a = a ^ b; // a = 10^20b = a ^ b; // b = (10^20)^20 = 10a = a ^ b; // a = (10^20)^10 = 20printf("a = %d, b = %d\n", a, b); // 輸出:a=20, b=10return 0;
}
- 求二進制中1的個數:
// 方法3(最優):每次消去最后一個1,循環次數=1的個數
#include <stdio.h>
int count_one(int num) {int count = 0;while (num) {num &= num - 1; // 消去最后一個1count++;}return count;
}
int main() {printf("%d\n", count_one(10)); // 1010 → 2個1 → 輸出2return 0;
}
6. 單目操作符
單目操作符僅需一個操作數,重點如下:
操作符 | 功能 | 示例 |
---|---|---|
! | 邏輯非(真變假,假變真) | !0 = 1 ,!5 = 0 |
++ | 自增(前置先增后用,后置先用后增) | int a=3; printf("%d", ++a); // 4 |
-- | 自減(類似++) | int a=3; printf("%d", a--); // 3 |
sizeof | 求類型/變量所占字節數 | sizeof(int) = 4 ,sizeof(a) = 4 (a為int) |
(類型) | 強制類型轉換 | (int)3.14 = 3 |
7. 逗號表達式
形式:exp1, exp2, ..., expN
- 執行順序:從左到右依次執行。
- 結果:最后一個表達式的值。
示例:
#include <stdio.h>
int main() {int a = 1, b = 2;int c = (a > b, a = b + 10, a, b = a + 1); // 執行:a>b(假)→ a=12 → 取a=12 → b=13 → 結果c=13printf("c = %d\n", c); // 輸出:13return 0;
}
8. 下標訪問與函數調用
-
下標訪問
[]
:操作數為數組名+索引,如arr[3]
等價于*(arr+3)
。int arr[5] = {1,2,3,4,5}; printf("%d\n", arr[2]); // 輸出:3(訪問第3個元素)
-
函數調用
()
:操作數為函數名+參數列表。#include <stdio.h> void print_hello() {printf("Hello, C!\n"); } int add(int a, int b) {return a + b; } int main() {print_hello(); // 函數調用,無參數printf("3+5 = %d\n", add(3, 5)); // 函數調用,有參數 → 輸出8return 0; }
9. 結構體成員訪問
結構體成員訪問有兩種方式:
.
:直接訪問(結構體變量)。->
:間接訪問(結構體指針)。
示例:
#include <stdio.h>
#include <string.h>// 定義學生結構體
struct Stu {char name[20];int age;
};int main() {struct Stu s = {"張三", 20}; // 結構體變量struct Stu* ps = &s; // 結構體指針// 訪問成員printf("name: %s, age: %d\n", s.name, s.age); // .訪問 → 張三, 20strcpy(ps->name, "李四"); // ->訪問:修改姓名ps->age = 22; // ->訪問:修改年齡printf("name: %s, age: %d\n", s.name, s.age); // 李四, 22return 0;
}
10. 操作符的優先級與結合性
表達式求值由優先級和結合性決定:
-
優先級:決定操作順序(如
*
優先級高于+
)。
例:3 + 4 * 5
→ 先算4*5=20
,再算3+20=23
。 -
結合性:優先級相同時,左結合(從左到右)或右結合(從右到左,如賦值
=
)。
例:5 * 6 / 2
→ 左結合,先算5*6=30
,再算30/2=15
。
優先級簡表(從高到低)
優先級 | 操作符 | 結合性 |
---|---|---|
1 | () 、[] 、. 、-> | 左結合 |
2 | ++ 、-- 、! 、~ 、sizeof | 右結合 |
3 | * 、/ 、% | 左結合 |
4 | + 、- (算術) | 左結合 |
5 | << 、>> | 左結合 |
6 | < 、> 、<= 、>= | 左結合 |
7 | == 、!= | 左結合 |
8 | & | 左結合 |
9 | ^ | 左結合 |
10 | ` | ` |
11 | && | 左結合 |
12 | ` | |
13 | ? : | 右結合 |
14 | = 、+= 、-= 等 | 右結合 |
11. 表達式求值注意事項
11.1 整型提升
長度小于int
的整型(如char
、short
)在運算時會提升為int
或unsigned int
,避免精度丟失。
例:char a = 127, b = 1; int c = a + b;
a
提升為00000000 00000000 00000000 01111111
b
提升為00000000 00000000 00000000 00000001
- 相加后
c = 128
(若直接存char
會溢出)。
11.2 避免歧義表達式
部分表達式因優先級/結合性無法確定唯一執行順序,結果依賴編譯器,應避免:
c + --c
:無法確定+
左右操作數的求值順序。(++i) + (++i) + (++i)
:不同編譯器結果不同(如GCC輸出10,VS輸出12)。
總結
操作符是C語言的基礎,掌握其分類、特性及求值規則,能幫助我們寫出更高效、無歧義的代碼。重點關注位操作符的靈活應用(如交換變量、統計1的個數)、補碼的存儲邏輯,以及優先級對表達式的影響。實際開發中,復雜表達式建議用括號明確順序,減少歧義。
希望本文對你理解C語言操作符有幫助,歡迎留言交流! 😊