引言
在C語言的浩瀚宇宙中,運算子如同點亮星辰的魔法棒,它們不僅連線著資料的海洋,更驅動著程式的邏輯流轉。從基礎的算術運算到複雜的位操作,每一個運算子都承載著特定的功能,是構建程式邏輯的基石。掌握C語言的運算子,就如同手握開啟程式設計世界大門的鑰匙,讓你能夠自如地編寫出高效、精準的程式碼。本文將帶你深入探索C語言的運算子世界一一解析它們的奧秘,助你在程式設計之路上越走越遠。
算術運算子
運算子 | 描述 | 示例 |
---|---|---|
+ |
加法運算子,用於將兩個數相加 | int result = 5 + 3; // 結果為 8 |
- |
減法運算子,用於從一個數中減去另一個數 | int result = 10 - 4; // 結果為 6 |
* |
乘法運算子,用於將兩個數相乘 | int result = 3 * 4; // 結果為 12 |
/ |
除法運算子,用於將第一個數除以第二個數 | int quotient = 10 / 2; // 結果為 5 float division = 10.0 / 3.0; // 結果為 3.333... |
% |
取模運算子(求餘),返回兩數相除的餘數 | int remainder = 10 % 3; // 結果為 1 |
++ |
自增運算子,將變數的值增加1 | int a = 5; a++; // a 的值變為 6 int b = 5; ++b; // b 的值同樣變為 6 |
-- |
自減運算子,將變數的值減少1 | int c = 5; c--; // c 的值變為 4 int d = 5; --d; // d 的值同樣變為 4 |
注意:
- 當使用
/
運算子進行整數除法時,結果會向下取整,即捨棄小數部分。 %
運算子的運算元必須是整數。- 自增(
++
)和自減(--
)運算子可以放在變數之前(字首形式)或之後(字尾形式),但在表示式中的行為可能有所不同。字首形式會先增加(或減少)變數的值,然後再進行其他操作;字尾形式則會先進行其他操作,然後再增加(或減少)變數的值。但在這個表格的示例中,我們主要關注它們的基本用法。
關係運算子
運算子 | 描述 | 示例 |
---|---|---|
== |
等於,比較兩個值是否相等 | if (5 == 3) { /* 這部分程式碼不會執行 */ } if (5 == 5) { /* 這部分程式碼會執行 */ } |
!= |
不等於,比較兩個值是否不相等 | if (5 != 3) { /* 這部分程式碼會執行 */ } if (5 != 5) { /* 這部分程式碼不會執行 */ } |
> |
大於,比較第一個值是否大於第二個值 | if (5 > 3) { /* 這部分程式碼會執行 */ } if (5 > 5) { /* 這部分程式碼不會執行 */ } |
< |
小於,比較第一個值是否小於第二個值 | if (3 < 5) { /* 這部分程式碼會執行 */ } if (5 < 3) { /* 這部分程式碼不會執行 */ } |
>= |
大於等於,比較第一個值是否大於或等於第二個值 | if (5 >= 5) { /* 這部分程式碼會執行 */ } if (3 >= 5) { /* 這部分程式碼不會執行 */ } |
<= |
小於等於,比較第一個值是否小於或等於第二個值 | if (3 <= 5) { /* 這部分程式碼會執行 */ } if (5 <= 3) { /* 這部分程式碼不會執行 */ } |
注意:
- 關係運算子用於比較兩個值,並返回一個布林結果(在C語言中,實際上是以整數形式返回,其中
0
表示false
,非0
值表示true
)。 - 這些運算子經常與
if
、while
、for
等控制流語句一起使用,以根據條件執行不同的程式碼塊。 - 在進行比較時,確保比較的資料型別相容,否則可能會引發編譯錯誤或意外的行為。例如,將整數與浮點數直接進行比較通常不是一個好主意,除非你有意為之並瞭解可能的結果。
邏輯運算子
運算子 | 描述 | 示例 |
---|---|---|
&& |
邏輯與(AND),僅當兩個運算元都為真時,結果才為真 | if (a > 0 && b > 0) { /* 當a和b都大於0時執行 */ } |
|| |
邏輯或(OR),當兩個運算元中至少有一個為真時,結果就為真 | if (a > 0 || b > 0) { /* 當a或b中至少有一個大於0時執行 */ } |
! |
邏輯非(NOT),用於反轉運算元的真假值 | if (!a) { /* 當a為假時執行 */ } 或 if (!(a > 0)) { /* 當a不大於0時執行 */ } |
注意:
- 邏輯運算子通常用於控制流語句(如
if
、while
、for
)中,以根據多個條件的組合來決定是否執行某個程式碼塊。 - 在C語言中,真值通常表示為非零值,而假值則表示為
0
。因此,邏輯運算子的運算元可以是任何整數表示式,其真假值取決於表示式的計算結果。 - 使用邏輯運算子時,應注意運算子的優先順序和結合性。通常,
!
運算子的優先順序最高,&&
和||
運算子的優先順序低於關係運算子和算術運算子,但高於賦值運算子。此外,&&
和||
運算子是左結合的,即它們從左到右評估運算元。 - 邏輯與(
&&
)運算子具有短路行為,即如果第一個運算元為假(即0
),則不會評估第二個運算元,因為整個表示式的結果已經確定為假。同樣,邏輯或(||
)運算子也具有短路行為,即如果第一個運算元為真(即非0
),則不會評估第二個運算元,因為整個表示式的結果已經確定為真。這種短路行為有時可以用於避免不必要的計算或潛在的副作用。
位運算子
運算子 | 描述 | 示例 |
---|---|---|
& |
按位與(AND),對兩個數的二進位制表示進行逐位與操作,只有對應的兩個二進位均為1時,結果位才為1 | int a = 5; // 二進位制: 0101 int b = 3; // 二進位制: 0011 int c = a & b; // 結果: 1, 二進位制: 0001 |
| |
按位或(OR),對兩個數的二進位制表示進行逐位或操作,只要對應的兩個二進位中有一個為1時,結果位就為1 | int a = 5; // 二進位制: 0101 int b = 3; // 二進位制: 0011 int c = a | b; // 結果: 7, 二進位制: 0111 |
^ |
按位異或(XOR),對兩個數的二進位制表示進行逐位異或操作,當對應的兩個二進位相異時,結果位為1 | int a = 5; // 二進位制: 0101 int b = 3; // 二進位制: 0011 int c = a ^ b; // 結果: 6, 二進位制: 0110 |
~ |
按位取反(NOT),對數的二進位制表示進行逐位取反操作,即0變1,1變0 | int a = 5; // 二進位制: 0101 int b = ~a; // 結果: -6, 二進位制(補碼): 11111010(注意:結果以補碼形式儲存,實際值需考慮資料型別和符號位) |
<< |
左移(Left Shift),將數的二進位制表示向左移動指定的位數,左側超出的位將被丟棄,右側新增的位將用0填充 | int a = 5; // 二進位制: 0101 int b = a << 2; // 結果: 20, 二進位制: 10100 |
>> |
右移(Right Shift),將數的二進位制表示向右移動指定的位數,對於有符號數,左側新增的位將用符號位填充(即正數用0填充,負數用1填充),右側超出的位將被丟棄 | int a = 5; // 二進位制: 0101 int b = a >> 2; // 結果: 1, 二進位制: 0001 int c = -5; // 假設為32位整數,二進位制(補碼): 11111111 11111111 11111111 11111011 int d = c >> 2; // 結果: -2, 二進位制(補碼): 11111111 11111111 11111111 11111110 |
注意:
- 位運算子的運算元通常是整數型別(如
int
、char
等),不能是浮點型別(如float
、double
)。 - 在進行位移操作時,特別是右移操作,對於有符號數,不同編譯器或平臺可能有不同的行為(即算術右移或邏輯右移),因此在跨平臺程式設計時需要特別注意。
- 位運算子常用於底層程式設計、硬體程式設計、效能最佳化等場景,它們允許程式設計師直接對資料的二進位制表示進行操作,從而實現高效的資料處理和演算法實現。
- 示例中的結果以十進位制形式給出,但為了說明位運算的過程,同時也給出了二進位制形式的說明(對於取反操作,由於結果以補碼形式儲存,因此直接給出了補碼形式的二進位制表示和對應的十進位制值)。在實際程式設計中,需要注意資料型別和符號位對結果的影響。
賦值運算子
運算子 | 描述 | 示例 |
---|---|---|
= |
簡單的賦值運算子,用於將右側表示式的值賦給左側的變數 | int a = 5; // 將5賦值給變數a |
+= |
加法賦值運算子,將右側表示式的值與左側變數的值相加,然後將結果賦值給左側變數 | a += 3; // 相當於 a = a + 3; 假設a之前的值為5,則執行後a的值為8 |
-= |
減法賦值運算子,將左側變數的值減去右側表示式的值,然後將結果賦值給左側變數 | a -= 2; // 相當於 a = a - 2; 假設a之前的值為8,則執行後a的值為6 |
*= |
乘法賦值運算子,將左側變數的值與右側表示式的值相乘,然後將結果賦值給左側變數 | a *= 2; // 相當於 a = a * 2; 假設a之前的值為6,則執行後a的值為12 |
/= |
除法賦值運算子,將左側變數的值除以右側表示式的值,然後將結果賦值給左側變數 | a /= 2; // 相當於 a = a / 2; 假設a之前的值為12,則執行後a的值為6 |
%= |
取模賦值運算子,將左側變數的值對右側表示式的值取模,然後將結果賦值給左側變數 | a %= 3; // 相當於 a = a % 3; 假設a之前的值為6,則執行後a的值為0 |
<<= |
左移賦值運算子,將左側變數的二進位制表示向左移動指定的位數(由右側表示式給出),然後將結果賦值給左側變數 | a <<= 1; // 相當於 a = a << 1; 假設a之前的值為6(二進位制: 0110),則執行後a的值為12(二進位制: 1100) |
>>= |
右移賦值運算子,將左側變數的二進位制表示向右移動指定的位數(由右側表示式給出),然後將結果賦值給左側變數 | a >>= 1; // 相當於 a = a >> 1; 假設a之前的值為12(二進位制: 1100),則執行後a的值為6(二進位制: 0110),對於有符號數,注意符號位的擴充套件 |
&= |
按位與賦值運算子,對左側變數的值和右側表示式的值進行按位與操作,然後將結果賦值給左側變數 | a &= 3; // 相當於 a = a & 3; 假設a之前的值為12(二進位制: 1100),則執行後a的值為0(二進位制: 0000),因為1100 & 0011 = 0000 |
|= |
按位或賦值運算子,對左側變數的值和右側表示式的值進行按位或操作,然後將結果賦值給左側變數 | a |= 3; // 相當於 a = a | 3; 假設a之前的值為4(二進位制: 0100),則執行後a的值為7(二進位制: 0111),因為0100 | 0011 = 0111 |
^= |
按位異或賦值運算子,對左側變數的值和右側表示式的值進行按位異或操作,然後將結果賦值給左側變數 | a ^= 3; // 相當於 a = a ^ 3; 假設a之前的值為4(二進位制: 0100),則執行後a的值為7(二進位制: 0111),因為0100 ^ 0011 = 0111 |
注意:
- 賦值運算子用於將表示式的值儲存到變數中。
- 複合賦值運算子(如
+=
、-=
等)是先進行指定的算術或位運算,然後將結果賦值給左側的變數,這種方式可以使程式碼更簡潔。 - 在使用位運算子(如
<<=
、>>=
、&=
、\|=
、^=
)時,需要注意運算元的資料型別和符號位的影響,特別是在進行右移操作時。 - 賦值運算的結果通常是賦值給左側的變數,但某些情況下(如在表示式中使用賦值運算子),其結果也可以被用於其他目的。然而,為了程式碼的可讀性和可維護性,建議避免在需要計算結果的表示式中使用賦值運算子。
雜項運算子
運算子 | 描述 | 示例 |
---|---|---|
sizeof |
用於獲取變數或資料型別所佔記憶體的大小(以位元組為單位) | size_t size = sizeof(int); // 獲取int型別所佔的位元組數,結果通常為4(取決於編譯器和平臺) |
& (地址運算子) |
獲取變數的記憶體地址 | int a = 5; int* ptr = &a; // ptr儲存了變數a的記憶體地址 |
* (解引用/間接訪問運算子) |
透過指標訪問其所指向的記憶體地址中的值 | int* ptr = &a; int value = *ptr; // value的值為5,即a的值 |
?: (條件運算子/三元運算子) |
根據條件表示式的真假來選擇兩個值中的一個 | int a = 10, b; b = (a > 5) ? 20 : 30; // b的值為20,因為a大於5 |
注意:
-
sizeof
運算子的返回值型別為size_t
,這是一個無符號整數型別,用於表示物件的大小。 -
地址運算子
&
用於獲取變數的記憶體地址,其結果是一個指向該變數型別的指標。 -
解引用/間接訪問運算子
*
用於透過指標訪問其所指向的記憶體地址中的值。如果指標未初始化或指向無效的記憶體地址,則解引用該指標可能導致未定義行為。 -
條件運算子
?:
是一個三元運算子,它接受三個運算元:條件表示式、當條件為真時返回的值、以及當條件為假時返回的值。其優先順序低於關係運算子和算術運算子,但高於賦值運算子。 -
雜項運算子在C語言中扮演著重要的角色,它們提供了對記憶體地址的直接操作、條件選擇等功能,是編寫高效、靈活C語言程式的關鍵。然而,由於它們直接操作記憶體地址或進行條件選擇,因此在使用時需要格外小心,以避免引入錯誤或安全問題。
運算子優先順序
優先順序 | 運算子 | 描述 | 用法示例 |
---|---|---|---|
1 | 括號 () |
用於改變運算的優先順序 | (a + b) * c |
2 | 自增 ++ 、自減 -- 、正負號 + 、- 、邏輯非 ! 、按位取反 ~ |
單目運算子,作用於單個運算元 | ++a , --b , +5 , -3 , !flag , ~x |
3 | 乘法 * 、除法 / 、取模 % |
雙目運算子,用於算術運算 | a * b , c / d , e % f |
4 | 加法 + 、減法 - |
雙目運算子,用於算術運算 | g + h , i - j |
5 | 左移 << 、右移 >> |
雙目運算子,用於位運算 | k << 2 , l >> 1 |
6 | 關係運算子(大於 > , 大於等於 >= , 小於 < , 小於等於 <= ) |
雙目運算子,用於比較運算元 | m > n , o >= p , q < r , s <= t |
7 | 等於 == 、不等於 != |
雙目運算子,用於比較運算元是否相等 | u == v , w != x |
8 | 按位與 & |
雙目運算子,用於位運算 | y & z |
9 | 按位異或 ^ |
雙目運算子,用於位運算 | a ^ b |
10 | 按位或 | |
雙目運算子,用於位運算 | c | d |
11 | 邏輯與 && |
雙目運算子,用於邏輯運算 | e && f |
12 | 邏輯或 || |
雙目運算子,用於邏輯運算 | g || h |
13 | 條件運算子 ?: |
三目運算子,根據條件選擇兩個值中的一個 | i > 0 ? i : -i |
14 | 賦值運算子 = 、+= 、-= 、*= 、/= 、%= 、&= 、^= 、|= 、<<= 、>>= |
用於將值賦給變數或進行復合賦值 | j = 5 , k += 3 |
15 | 逗號運算子 , |
用於分隔表示式,並返回最後一個表示式的值 | m = 1, n = 2, m + n (結果為3,但m和n也被賦值) |
注意: |
-
運算子優先順序決定了在一個表示式中各個運算子的執行順序。當表示式中存在多個運算子時,優先順序高的運算子會先進行計算。
-
可以透過使用括號()來改變運算子的優先順序,使得括號內的表示式先被計算。
-
賦值運算子的優先順序相對較低,這意味著在複雜的表示式中,賦值操作通常會在其他算術、邏輯或位運算之後進行。
-
逗號運算子,用於分隔多個表示式,並返回最後一個表示式的值。它在所有運算子中具有最低的優先順序,因此逗號兩邊的表示式會按照從左到右的順序依次計算。
請注意,雖然這個表格提供了C語言運算子優先順序的基本概述,但在實際程式設計中,為了程式碼的可讀性和易於理解,建議儘量使用括號來明確表示式的計算順序。