C語言運算子深度解析--超詳細

Childbro發表於2024-08-01

引言

在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)。
  • 這些運算子經常與ifwhilefor等控制流語句一起使用,以根據條件執行不同的程式碼塊。
  • 在進行比較時,確保比較的資料型別相容,否則可能會引發編譯錯誤或意外的行為。例如,將整數與浮點數直接進行比較通常不是一個好主意,除非你有意為之並瞭解可能的結果。


邏輯運算子

運算子 描述 示例
&& 邏輯與(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時執行 */ }

注意:

  • 邏輯運算子通常用於控制流語句(如ifwhilefor)中,以根據多個條件的組合來決定是否執行某個程式碼塊。
  • 在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

注意

  1. 位運算子的運算元通常是整數型別(如intchar等),不能是浮點型別(如floatdouble)。
  2. 在進行位移操作時,特別是右移操作,對於有符號數,不同編譯器或平臺可能有不同的行為(即算術右移或邏輯右移),因此在跨平臺程式設計時需要特別注意。
  3. 位運算子常用於底層程式設計、硬體程式設計、效能最佳化等場景,它們允許程式設計師直接對資料的二進位制表示進行操作,從而實現高效的資料處理和演算法實現。
  4. 示例中的結果以十進位制形式給出,但為了說明位運算的過程,同時也給出了二進位制形式的說明(對於取反操作,由於結果以補碼形式儲存,因此直接給出了補碼形式的二進位制表示和對應的十進位制值)。在實際程式設計中,需要注意資料型別和符號位對結果的影響。


賦值運算子

運算子 描述 示例
= 簡單的賦值運算子,用於將右側表示式的值賦給左側的變數 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

注意

  1. sizeof運算子的返回值型別為size_t,這是一個無符號整數型別,用於表示物件的大小。

  2. 地址運算子&用於獲取變數的記憶體地址,其結果是一個指向該變數型別的指標。

  3. 解引用/間接訪問運算子*用於透過指標訪問其所指向的記憶體地址中的值。如果指標未初始化或指向無效的記憶體地址,則解引用該指標可能導致未定義行為。

  4. 條件運算子?:是一個三元運算子,它接受三個運算元:條件表示式、當條件為真時返回的值、以及當條件為假時返回的值。其優先順序低於關係運算子和算術運算子,但高於賦值運算子。

  5. 雜項運算子在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也被賦值)
注意
  1. 運算子優先順序決定了在一個表示式中各個運算子的執行順序。當表示式中存在多個運算子時,優先順序高的運算子會先進行計算。

  2. 可以透過使用括號()來改變運算子的優先順序,使得括號內的表示式先被計算。

  3. 賦值運算子的優先順序相對較低,這意味著在複雜的表示式中,賦值操作通常會在其他算術、邏輯或位運算之後進行。

  4. 逗號運算子,用於分隔多個表示式,並返回最後一個表示式的值。它在所有運算子中具有最低的優先順序,因此逗號兩邊的表示式會按照從左到右的順序依次計算。

請注意,雖然這個表格提供了C語言運算子優先順序的基本概述,但在實際程式設計中,為了程式碼的可讀性和易於理解,建議儘量使用括號來明確表示式的計算順序。

相關文章