19 C 語言位運算、賦值、條件、逗號運算符詳解:涵蓋運算符優先級與復雜表達式計算過程分析

1 位運算符

????????位運算符是對整數的二進制表示(補碼形式)進行逐位操作的運算符。以下是主要的位運算符及其功能描述:

運算符描述操作數個數副作用
&按位與2
|按位或2
^按位異或2
~按位取反1
<<按位左移2
>>按位右移2

1.1 按位與 &

  • 運算規則:對于兩個數的每一位,如果兩個相應的位都為 1,則結果的該位為 1;否則,結果的該位為 0(遵循 “有 0 為 0,全 1 為 1” 規則)
  • 示例:5 & 3
    • 5 的二進制表示:0101
    • 3 的二進制表示:0011
    • 按位與操作過程:
    0 1 0 1  
&  0 0 1 1  -------  0 0 0 1結果:0001(十進制1)

1.2 按位或 |

  • 運算規則:對于兩個數的每一位,如果兩個相應的位中至少有一個為 1,則結果的該位為 1;如果兩個相應的位都為 0,則結果的該位為 0(遵循 “有 1 為 1,全 0 為 0” 規則)
  • 示例:5 | 3
    • 5 的二進制表示:0101
    • 3 的二進制表示:0011
    • 按位或操作過程:
    0 1 0 1  
|  0 0 1 1  -------  0 1 1 1結果:0111(十進制7)

1.3 按位異或 ^

  • 計算規則:對于兩個數的每一位,如果兩個相應的位不同(一個為 1,另一個為 0),則結果的該位為 1;如果兩個相應的位相同(都為 0 或都為 1),則結果的該位為 0。(遵循 “相同為 0,不同為 1” 規則)
  • 示例:5 ^ 3
    • 5 的二進制表示:0101
    • 3 的二進制表示:0011
    • 按位異或操作過程:
    0 1 0 1  
^  0 0 1 1  -------  0 1 1 0結果:0110(十進制6)

????????為了清晰展示 8 位二進制數的位運算過程,我們可以使用 char?類型來進行按位與、按位或和異或操作的演示。由于 char?類型通常占用 8 位,非常適合作為位運算的示例載體。程序如下:

#include <stdio.h>int main()
{// 使用 char 類型(通常是 8 位)char a = 17;  // 二進制表示為 0001 0001char b = -12; // -12 的補碼表示為 1111 0100// 按位與操作 &// 計算規則:【有 0 為 0,全 1 為 1】//   0001 0001  ->  17// &//   1111 0100  ->  -12//   0001 0000  ->  16printf("a & b = %d\n", a & b); // 輸出為 16// 按位或操作 |// 計算規則:【有 1 為 1,全 0 為 0】//   0001 0001  ->  17// |//   1111 0100  ->  -12//   1111 0101  ->  -11printf("a | b = %d\n", a | b); // 輸出為 -11// 按位異或操作 ^// 計算規則:【相同為 0,不同為 1】//   0001 0001  ->  17// ^//   1111 0100  ->  -12//   1110 0101  ->  -27printf("a ^ b = %d\n", a ^ b); // 輸出為 -27return 0;
}

????????程序計算過程分析:

????????程序在 VS Code 中的運行結果如下所示:

1.4?按位取反 ~

  • 計算規則:對一個數的二進制表示中的每一位(包括符號位)進行取反操作,即將所有的 0 變為 1,所有的 1 變為 0
  • 示例:例如,對于 char 類型(8 位)整數 17
    • 其二進制表示為 0001 0001
    • 按位取反后變為 1110 1110
    • 結果為 -18
#include <stdio.h>int main()
{// 使用 char 類型(通常是 8 位)char a = 17;  // 二進制表示為 0001 0001char b = -12; // -12 的補碼表示為 1111 0100// 按位取反操作 ~a//   0001 0001  ->  17// ~//   1110 1110  ->  -18printf("~a = %d\n", ~a); // 輸出為 -18// 按位非操作 ~b//   1111 0100  ->  -12// ~//   0000 1011  ->  11printf("~b = %d\n", ~b); // 輸出為 11return 0;
}

????????程序計算過程分析:

????????程序在 VS Code 中的運行結果如下所示:

1.5 按位左移 <<

  • 功能:將一個數的二進制表示向左移動指定的位數。左移時,左側邊緣超出的位將被丟棄,而在右側邊緣新增的位將用 0 填充

  • 語法:a << b

    • a?是要被左移的數
    • b?是指定左移的位數
  • 計算規則:

    • 移動操作:將 a 的二進制表示(補碼)向左移動 b 位。
    • 填充規則:
      • 左側邊緣超出的位將被丟棄
      • 在右側邊緣新增的位用 0 填充
  • 注意事項:

    • 未定義行為:如果指定左移的位數 b 是負數,則行為是未定義的(Undefined Behavior, UB)
    • 整數溢出:左移后的值可能超出該整數類型的表示范圍,導致整數溢出
    • 數學應用:左移操作通常用于將數乘以 2 的冪次方(假設沒有溢出)
    • 無符號整數:對于無符號整數,左移后的結果將保持為無符號數
    • 有符號整數:對于有符號整數,左移可能導致符號位的變化,進而影響整數的正負。例如,一個正數左移后符號位變為 1,那么結果將是一個負數。
  • 示例:5 << 1

    • 5 的八位二進制表示為:0000 0101
    • 左移 1 位后為 0000 1010,即十進制數 10
    • 左移 1 位相當于乘以 2 的 1 次方,即 5 * 2^1 = 10
#include <stdio.h>int main()
{// 演示未定義行為int a = 17;int undefined_shift = -1;int result = a << undefined_shift;printf("負數移位是未定義行為,示例: %d << %d = %d \n", a, undefined_shift, result); // 輸出可能是任意值// 演示數學應用int b = 5;// 左移操作通常用于將數乘以 2 的冪次方(假設沒有溢出)printf("%d << 4 = %d (5 * 2^4 = 80)\n", b, b << 4); // 輸出為 80// 演示無符號整數unsigned int e = 17;printf("無符號整數示例: %u << 2 = %u\n", e, e << 2); // 輸出為 68// 演示有符號整數int f = -12;printf("有符號整數示例: %d << 2 = %d\n", f, f << 2); // 輸出為 -48return 0;
}

????????程序計算過程分析:

????????程序在 VS Code 中的運行結果如下所示:

1.6 按位右移 >>

  • 功能:將一個數的二進制表示向右移動指定的位數。右移時,右側邊緣超出的位將被丟棄,而左側邊緣新增的位根據整數的類型(有符號還是無符號)有不同的填充規則
  • 語法:a >> b
    • a?是要被右移的數
    • b?是指定右移的位數
  • 計算規則:
    • 移動操作:將 a 的二進制表示(補碼)向右移動 b 位。
    • 填充規則:
      • 右側邊緣超出的位將被丟棄
      • 無符號整數:表現為邏輯右移,即左側用 0 填充
      • 有符號整數:在左側邊緣新增的位的填充規則依賴于編譯器的實現,通常是算術右移,即用符號位填充,但這不是標準強制要求的
  • 算術右移 (Arithmetic Right Shift):
    • 功能:在右移時,左側空出的位用符號位填充
    • 效果:保持數值的符號不變
    • 適用:用于有符號整數類型(如 int、char 等)
    • 示例:-10 >> 1
      • -10 的二進制表示為 1111 0110(假設 8 位系統)
      • 算術右移 1 位后為 1111 1011,即 -5
  • 邏輯右移 (Logical Right Shift):
    • 功能:在右移時,左側空出的位用 0 填充
    • 效果:不保持數值的符號,適用于無符號數
    • 適用:用于無符號整數類型(如 unsigned int、unsigned char 等)
    • 示例:10 >> 1
      • 10 的二進制表示為 0000 1010
      • 邏輯右移 1 位后為 0000 0101,即 5
  • 注意事項:
    • 未定義行為:如果指定右移的位數 b 是負數,則行為是未定義的(Undefined Behavior, UB)
    • 數學應用:對于無符號整數,右移操作通常用于將數除以 2 的冪次方(結果總是向下取整)
    • 實現依賴:對于有符號整數,C 標準沒有規定必須使用算術右移還是邏輯右移,這取決于編譯器的具體實現
#include <stdio.h>int main()
{// 演示未定義行為int a = 256;int undefined_shift = -2;int result = a >> undefined_shift;printf("負數移位是未定義行為,示例: %d >> %d = %d \n", a, undefined_shift, result); // 輸出可能是任意值// 演示無符號整數的邏輯右移unsigned int b = 17;printf("無符號整數示例: %u >> 3 = %u\n", b, b >> 3); // 輸出為 2// 演示有符號整數的算術右移int c = -12;printf("有符號整數示例: %d >> 3 = %d\n", c, c >> 3); // 輸出為 -2// 演示算術右移和邏輯右移的區別unsigned int d = 128;printf("無符號整數(邏輯右移)示例: %u >> 1 = %u\n", d, d >> 1); // 輸出為 64int e = -128;printf("有符號整數(算術右移)示例: %d >> 1 = %d\n", e, e >> 1); // 輸出為 -64// 演示數學應用// 對于無符號整數,右移操作通常用于將數除以 2 的冪次方(結果總是向下取整)int f = 85;printf("%d >> 3 = %d (85 / 2^3 = 10)\n", f, f >> 3); // 輸出為 10 (85/8 = 10.625,向下取整為 10)// 對于有符號整數,右移操作的行為依賴于編譯器的實現// 需看編譯器使用算術右移還是邏輯右移int g = -80;printf("%d >> 3 = %d (-80 / 2^3 = -10)\n", g, g >> 3); // 輸出為 -10 (-80/8 = -10)return 0;
}

????????程序計算過程分析:

????????程序在 VS Code 中的運行結果如下所示:

1.7?位運算符的意義與應用?

????????在 C 語言中,位運算符(包括按位與 &、按位或 |、按位異或 ^、按位非 ~、左移 << 和右移 >>)提供了對整數類型底層二進制位的直接操作能力。這類操作在系統級或嵌入式編程中尤為重要,特別是在需要精確控制硬件寄存器、標志位或其他底層資源的場景中。

????????位運算的核心應用之一是對特定比特位的置位(設為 1)和復位(設為 0),而不會影響其他位的狀態。例如:

  • 將第 n 位置為 1:使用按位或操作結合掩碼 (1 << n),即執行 x |= (1 << n);
    • (1 << n)

      • 這是創建一個掩碼(mask),它的作用是生成一個只有第 n 位為 1,其余都為 0 的數。例如:

        • 1 << 0 → 0b00000001 (第 0 位為 1)

        • 1 << 1 → 0b00000010 (第 1 位為 1)

        • 1 << 3 → 0b00001000 (第 3 位為 1)

      • 注意:通常從右往左數位,最低位是第 0 位。

    • x | (1 << n)

      • 用原來的值 x 和這個掩碼做按位或操作

      • 因為 OR 的規則是:只要有 1 就為 1。

      • 所以無論原來第 n 位是 0 還是 1,經過 OR 后都會變成 1

  • 將第 n 位置為 0:使用按位與操作結合取反后的掩碼 ~(1 << n),即執行 x &= ~(1 << n);
    • (1 << n)

      • 同上,先生成一個只有第 n 位為 1 的掩碼

    • ?~(1 << n)

      • 對這個掩碼取反。原來是 0b00001000,取反后變成 0b11110111

      • 這樣我們就得到了一個除了第 n 位是 0,其他都是 1 的掩碼。

    • x & ~(1 << n)

      • 將 x 和這個新掩碼進行按位與操作

      • AND 的規則是:只要有一個是 0,結果就是 0。

      • 所以:

        • 第 n 位一定是 0(因為它和掩碼中的 0 做 AND)

        • 其他位保持原樣(因為掩碼中是 1,所以保留原來的值)

????????這些操作允許程序員高效地修改寄存器中的某些位,從而實現對硬件狀態(如高低電平控制)的精細管理。由于位運算直接作用于數據的二進制表示,它們通常具有較高的執行效率,適合對性能敏感或資源受限的環境。


2 賦值運算符

????????在 C 語言中,賦值運算符用于將一個值賦予變量或表達式,它們是編程中非常基礎且重要的操作。以下是 C 語言中常見的賦值運算符及其用法。

運算符描述操作數個數表達式的值副作用
=賦值2左邊操作數的值(賦值后的值)有,左邊操作數的值被更新
+=相加賦值2左邊操作數的值(相加后的值)有,左邊操作數的值被更新
-=相減賦值2左邊操作數的值(相減后的值)有,左邊操作數的值被更新
*=相乘賦值2左邊操作數的值(相乘后的值)有,左邊操作數的值被更新
/=相除賦值2左邊操作數的值(相除后的值)有,左邊操作數的值被更新
%=取余賦值2左邊操作數的值(取余后的值)有,左邊操作數的值被更新
<<=左移賦值2左邊操作數的值(左移后的值)有,左邊操作數的值被更新
>>=右移賦值2左邊操作數的值(右移后的值)有,左邊操作數的值被更新
&=按位與賦值2左邊操作數的值(按位與后的值)有,左邊操作數的值被更新
^=按位異或賦值2左邊操作數的值(按位異或后的值)有,左邊操作數的值被更新
|=按位或賦值2左邊操作數的值(按位或后的值)有,左邊操作數的值被更新

2.1 左值和右值

  • 左值(Lvalue):左值是一個具有確定內存位置的變量或表達式,可以出現在賦值操作的左側。例如:變量名、數組元素、結構體成員等。
  • 右值(Rvalue):右值是一個表示值的表達式,但沒有明確的內存位置。右值通常是一個常量、算術表達式的結果、函數調用返回的結果等。

2.2 注意事項

  • 賦值運算符的第一個操作數(左值)必須是變量的形式,第二個操作數可以是任何形式的表達式
  • 左值必須可修改:賦值操作要求左側必須是一個左值,即一個可以存儲新值的內存位置
  • 右值提供值:賦值操作的右側可以是一個右值,它提供了要賦給左值的具體值。
  • 示例:

    • 正確用法:a = b + 25;(a 是左值,b + 25 是右值)
    • 錯誤用法:b + 25 = a;(嘗試將右值 b + 25 用作左值,這是不允許的)
    • 編譯錯誤結果,如下圖所示:

2.3 復合賦值運算符的使用

????????復合賦值運算符(如 +=、-= 等)的用法是將等號右邊的表達式首先計算為一個整體的值,然后將這個值與等號左邊的變量進行相應的運算,并將結果賦值回該變量

a += b + 2; 
等價于
a = a + (b + 2);

2.4 案例演示

#include <stdio.h>int main()
{int a = 10, b = 20, c = 30, d = 4;// 簡單的賦值a = 5;printf("a = %d\n", a); // a = 5// 加法賦值c += 3;                // c = c + 3 = 30 + 3printf("c = %d\n", c); // c = 33// 減法賦值c -= b;                // c = c - b = 33 - 20printf("c = %d\n", c); // c = 13// 乘法賦值a *= 2;                // a = a * 2 = 5 * 2printf("a = %d\n", a); // a = 10// 除法賦值b /= 2;                // b = b / 2 = 20 / 2printf("b = %d\n", b); // b = 10// 取模賦值c %= 3;                // c = c % 3 = 13 % 3printf("c = %d\n", c); // c = 1// 連等寫法int e = 12, f;f = e *= a; // f = e * a = 12 * 10// 先計算 e *= a,然后將結果賦值給 fprintf("e = %d\n", e); // e = 120printf("f = %d\n", f); // f = 120// 左移賦值d <<= 2;               // d = d << 2 = 4 << 2printf("d = %d\n", d); // d = 16// 右移賦值d >>= 1;               // d = d >> 1 = 16 >> 1printf("d = %d\n", d); // d = 8// 按位與賦值a &= 1;                // a = a & 1 = 10 & 1printf("a = %d\n", a); // a = 0// 按位異或賦值b ^= 3;                // b = b ^ 3 = 10 ^ 3printf("b = %d\n", b); // b = 9// 按位或賦值b |= 4;                // b = b | 4 = 9 | 4printf("b = %d\n", b); // b = 13return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

2.5?復合賦值運算符表達式的值

????????在 C 語言中,復合賦值運算符(如 +=、-=、*= 等)不僅簡化了賦值操作,還具有特定的表達式值。復合賦值運算符組成的表達式,其值為賦值后的左邊操作數的值。以下通過一個案例來演示這一特性:

#include <stdio.h>int main()
{int n = 5;// 使用復合賦值運算符 +=,并打印表達式的結果printf("n += 3 的結果是: %d\n", n += 3);// 執行過程:// 1. 計算 n + 3 = 8// 2. 將 8 賦給 n// 3. 表達式 n += 3 的值為賦值后的 n 的值,即 8// 輸出:n += 3 的結果是: 8// 驗證 n 的值printf("此時 n 的值是: %d\n", n); // 輸出:此時 n 的值是: 8return 0;
}
  • 初始時,n 的值為 5。
  • 執行 n += 3 時,先計算 n + 3 的值(即 8),然后將該值賦給 n。
  • 表達式 n += 3 的值為賦值后的 n 的值,即 8,因此 printf 函數會輸出 8。
  • 最后,再次打印 n 的值,確認 n 已經被更新為 8。

????????程序在 VS Code 中的運行結果如下所示:

2.6?連等寫法

????????C 語言支持連等寫法,即在一個表達式中連續進行多個賦值操作。連等寫法的賦值順序是從右向左進行。以下通過一個案例來演示連等寫法:

#include <stdio.h>int main()
{int x, y;// 使用連等寫法 x = y = 99x = y = 99;// 執行過程解析:// 1. y = 99; 先執行,將 y 賦值為 99// 2. 然后 x = y; 執行,將 x 賦值為 y 的值,即 99// 打印 x 和 y 的值printf("x = %d, y = %d\n", x, y); // 輸出:x = 99, y = 99return 0;
}
  • 在 x = y = 99; 這個連等寫法中,賦值操作是從右向左進行的。
  • 首先,99 被賦給 y,此時 y 的值為 99。
  • 然后,y 的值(即 99)被賦給 x,此時 x 的值也為 99。
  • 最終,printf 函數輸出 x = 99, y = 99,驗證了連等寫法的執行順序和賦值過程。

????????程序在 VS Code 中的運行結果如下所示:


3 三元運算符

3.1 基本語法

????????三元運算符(也稱為條件運算符)的基本語法如下:

條件表達式 ? 表達式1 : 表達式2;
  • 條件表達式:一個邏輯表達式,用于判斷其真假。
  • 表達式1:如果條件表達式為真(非 0),則整個三元運算符的值為表達式 1 的值
  • 表達式2:如果條件表達式為假(0),則整個三元運算符的值為表達式 2 的值

3.2?案例演示

#include <stdio.h>int main()
{int a = 99;int b = 99;// 使用三元運算符來決定 res 的值int res = a > b ? a++ : b--;// 因為 a 不大于 b,所以執行 b--,并將結果賦值給 res// 注意:b-- 是后綴自減,意味著先返回 b 的當前值(99),然后再將 b 減 1// res 被賦值為 99,然后 b 變為 98printf("a=%d\n", a);     // 輸出 a=99,因為 a 沒有被改變printf("b=%d\n", b);     // 輸出 b=98,因為 b 在前面的條件運算符中自減了printf("res=%d\n", res); // 輸出 res=99,因為 res 被賦值為 b 自減之前的值float n1 = a > b ? 1.1 : 1.2; // 條件表達式為真,整個表達式的值是表達式1:1.1// 注意:由于 b 在前面的條件運算符中已經被自減,所以這里 b 的值是 98printf("n1=%.2f\n", n1); // 輸出 n1=1.10return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

3.3?案例:計算兩個數的最大值

#include <stdio.h>int main()
{int a = 10;int b = 100;// 使用三元運算符計算 a 和 b 中的最大值int max = a > b ? a : b;printf("a 和 b 中最大的數字:%d", max); // 輸出:a 和 b 中最大的數字:100return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

3.4?案例:計算三個數的最大值

#include <stdio.h>int main()
{int a = 10;int b = 100;int c = 199;// 1. 使用兩次三元運算符來計算 a、b 和 c 中的最大值int max_a_b = a > b ? a : b;int max_a_b_c = max_a_b > c ? max_a_b : c;// 輸出 a、b 和 c 中最大的數字printf("a、b、c 中最大的數字:%d\n", max_a_b_c); // 輸出:a、b、c 中最大的數字:199// 2. 使用嵌套的三元運算符來找出 a、b、c 中的最大值// 首先比較 a 和 b,然后將較大的值與 c 比較int max = (a > b ? a : b) > c ? (a > b ? a : b) : c;// 輸出 a、b 和 c 中最大的數字printf("a、b、c 中最大的數字:%d\n", max); // 輸出:a、b、c 中最大的數字:199// 3. 也可以簡化為下面的寫法:max = (a > b ? (a > c ? a : c) : (b > c ? b : c));// 輸出 a、b 和 c 中最大的數字printf("a、b、c 中最大的數字:%d\n", max); // 輸出:a、b、c 中最大的數字:199// 4. 也可以使用 if-else 語句來找出 a、b、c 中的最大值// 后續在學習 if-else 語句時會詳細講解return 0;
}

????????程序在 VS Code 中的運行結果如下所示:


4 逗號運算符

4.1 基本語法

????????逗號運算符(,)是 C 語言中一個簡單但強大的運算符,用于將多個表達式連接在一起。它的基本語法如下:

表達式1, 表達式2, 表達式3, ..., 表達式N;
  • 表達式1, 表達式2, ..., 表達式N:這些是逗號運算符連接的多個表達式。

4.2 表達式的值

????????逗號運算符的特性如下:

  • 求值順序:逗號運算符從左到右依次計算每個表達式的值
  • 表達式的值:整個逗號表達式的值為最后一個表達式的值

4.3 案例演示

#include <stdio.h>int main()
{int a = 5, b = 10, c = 15;// 使用逗號運算符依次執行多個表達式int result = (a = b, b = c, c = a + b);// 執行過程解析:// 1. a = b,將 b 的值賦給 a,此時 a = 10, b = 10, c = 15// 2. b = c,將 c 的值賦給 b,此時 a = 10, b = 15, c = 15// 3. c = a + b,將 a 和 b 的和賦給 c,此時 a = 10, b = 15, c = 25// 最后,result 被賦值為 c 的值,即 25// 打印結果printf("a = %d, b = %d, c = %d\n", a, b, c); // 輸出:a = 10, b = 15, c = 25printf("result = %d\n", result);             // 輸出:result = 25return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

4.4 使用場景

????????逗號運算符通常用于以下場景:

  • 簡化代碼:在需要執行多個操作但不想使用多行代碼時,可以使用逗號運算符。
  • 循環和條件語句:在 for 循環的初始化或更新部分,或者在需要多個條件判斷的地方,可以使用逗號運算符

4.5 注意事項

  • 可讀性:雖然逗號運算符可以簡化代碼,但過度使用可能會降低代碼的可讀性。
  • 優先級:逗號運算符的優先級較低,因此在復雜的表達式中,建議使用括號來明確運算順序。

5 運算符優先級

5.1 運算符優先級表格說明

優先級運算符名稱或含義結合方向
1[]數組下標左到右
()函數調用、圓括號
.成員選擇(對象)
->成員選擇(指針)
2-(單目)負號運算符右到左
(類型)強制類型轉換
++自增運算符
--自減運算符
*(單目)取值運算符(解引用)
&(單目)取地址運算符
!邏輯非運算符
~按位取反運算符
sizeof長度運算符
3/左到右
*(雙目)
%余數(取模)
4+左到右
-(雙目)
5<<左移左到右
>>右移
6>大于左到右
>=大于等于
<小于
<=小于等于
7==等于左到右
!=不等于
8&按位與左到右
9^按位異或左到右
10|按位或左到右
11&&邏輯與左到右
12||邏輯或左到右
13?:條件運算符右到左
14=賦值運算符右到左
/=除后賦值
*=乘后賦值
%=取模后賦值
+=加后賦值
-=減后賦值
<<=左移后賦值
>>=右移后賦值
&=按位與后賦值
^=按位異或后賦值
|=

按位或后賦

15,逗號運算符左到右
  • 優先級記憶:雖然運算符優先級表看起來復雜,但通常不需要刻意記憶所有優先級。一般來說,一元運算符(如 !、-(單目)、++、-- 等)的優先級高于算術運算符,算術運算符的優先級高于關系運算符,關系運算符的優先級高于邏輯運算符,邏輯運算符的優先級高于三元運算符,三元運算符的優先級高于賦值運算符
  • 常用優先級關系:自增自減 >?邏輯非 ! > 算術運算符 > 關系運算符 > 邏輯與 && > 邏輯或 || > 條件運算符 ?: > 賦值運算符
  • 使用括號:如果對運算符的優先級不確定,或者為了代碼的可讀性,可以直接使用括號來明確運算順序。括號可以覆蓋任何運算符的優先級,確保表達式按照預期的方式計算。

5.2 復雜表達式的計算分析

表達式 5 > 3 && 8 < 4 - !0 的計算過程分析

????????問題:對于表達式 5 > 3 && 8 < 4 - !0 的最終值是多少?計算過程是怎樣的?

????????計算過程:

  1. 短路性質:首先計算 && 左邊的表達式 5 > 3,其邏輯值為 1。
  2. 右邊表達式:計算 && 右邊的表達式 8 < 4 - !0。
    • 非運算:!0 的邏輯值為 1。
    • 算術運算:4 - 1 的結果為 3。
    • 關系運算:8 < 3 的邏輯值為 0。
  3. 邏輯與運算:整個表達式的值為 1 && 0,最終邏輯值為 0。

表達式 a + b < c && b == c && a || b + c && b + c 的計算過程分析

????????問題:若 a = 2,b = 3,c = 4,表達式 a + b < c && b == c && a || b + c && b + c 的計算過程是怎樣的?值為多少?

????????計算過程:

  1. 短路性質:首先計算 a + b < c,即 2 + 3 < 4,其邏輯值為 0。
  2. 短路效果:b == c && a 不會執行,|| 左邊的值為 0。
  3. 右邊表達式:計算 b + c && b + c。
    • 算術運算:b + c 的結果為 7。
    • 邏輯與運算:7 && 7 的邏輯值為 1。
  4. 邏輯或運算:0 || 1 的邏輯值為 1。

表達式 (m = a > b) && (n = c > d) 的計算過程分析

????????問題:設有 int a = 1, b = 2, c = 3, d = 4, m = 2, n = 2;執行 (m = a > b) && (n = c > d) 后 m 和 n 的值分別是多少?表達式的結果是多少?

????????計算過程:

  1. 短路性質:首先計算(m = a > b)。
    • 關系比較:a > b,即 1 > 2,其邏輯值為 0。
    • 賦值運算:m = 0。
  2. 短路效果:(n = c > d) 不執行。
  3. 最終結果:
    • m 的值為 0。
    • n 的值為 2。
    • 整個表達式的結果為 0。

總結與建議:

  1. 避免復雜表達式:盡量簡化表達式。
  2. 明確執行順序:使用小括號明確執行順序,避免依賴運算符優先級。
  3. 拆分表達式:復雜表達式拆分為多個步驟,提高可讀性和可維護性。

6 編程練習

6.1?會員折扣

????????某商店對會員提供折扣:

  • 消費滿 100 元,打 9 折
  • 消費滿 200 元,打 8 折
  • 否則,無折扣

????????編寫一個程序,根據消費金額計算最終價格。

#include <stdio.h>int main()
{float amount; // 消費金額printf("請輸入消費金額:");scanf("%f", &amount); // 輸入消費金額float final_amount = (amount >= 200) ? amount * 0.8 : (amount >= 100) ? amount * 0.9: amount;printf("最終價格:%.2f 元\n", final_amount);return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

6.2 多任務處理

????????假設你在管理一個任務列表,每個任務有 ID、優先級和狀態。編寫一個程序,更新任務的狀態和優先級,并輸出更新后的信息。

#include <stdio.h>int main()
{int task_id = 101, priority = 3, status = 0;// 更新任務優先級和狀態int updated = (priority = 5, status = 1);printf("任務 ID:%d,優先級:%d,狀態:%d\n", task_id, priority, status);return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

6.3?燈的開關狀態

????????你有一個 8 位的整數表示 8 個燈的狀態(1 表示開,0 表示關)。初始狀態為所有燈關閉。編寫一個程序,打開第 2 和第 7 個燈,并關閉第 4 個燈(如果它是開的)。

#include <stdio.h>int main()
{unsigned char lights = 0b00000000; // 所有燈關// 打開第 2 和第 7 個燈lights |= (1 << 1) | (1 << 6);// 關閉第 4 個燈(如果它是開的)lights &= ~(1 << 3);return 0;
}

6.4?權限檢查

????????在一個系統中,權限使用一個整數的二進制位表示。例如,0000 1010 表示用戶有權限 2 和 4(從右到左,最低位為權限 1)。編寫一個程序,給用戶添加權限 3,并檢查用戶是否有權限 4。

#include <stdio.h>int main()
{unsigned char permissions = 0b00001000; // 初始權限// 添加權限 3permissions |= (1 << 2);// 檢查是否有權限 4int has_permission_4 = (permissions & (1 << 3)) != 0;// 解釋上面這行代碼// (permissions & (1 << 3)) != 0// permissions & (1 << 3) 是將 permissions 的第 3 位與 1 進行按位與操作,如果第 3 位為 1,則結果為 1,否則為 0。// != 0 是判斷結果是否不等于 0,如果不等于 0,則表示第 3 位為 1,即有權限 4,否則沒有權限 4。// 加上 != 0 使得代碼更加規范,因為 (permissions & (1 << 3)) 的結果是一個整數,而不是一個布爾值。printf("用戶是否有權限 4?%s\n", has_permission_4 ? "有" : "無");return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

6.5?溫度更新

????????假設你有一個初始溫度值為 25 攝氏度。由于天氣變化,溫度變化如下:

  1. 上午升溫 3 度。
  2. 下午降溫 2 度。
  3. 晚上升溫 1 度。

????????編寫一個程序,計算晚上的最終溫度。

#include <stdio.h>int main()
{float temperature = 25;temperature += 3; // 上午升溫temperature -= 2; // 下午降溫temperature += 1; // 晚上升溫printf("晚上的最終溫度:%.2f 攝氏度\n", temperature);return 0;
}

????????程序在 VS Code 中的運行結果如下所示:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83863.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83863.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83863.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

哈希查找方法

已知哈希表長度為11&#xff0c;哈希函數為H&#xff08;key&#xff09;&#xff1d;key&#xff05;11&#xff0c;隨機產生待散列的小于50的8個元素&#xff0c;同時采用線性探測再散列的方法處理沖突。任意輸入要查找的數據&#xff0c;無論是否找到均給出提示信息。 int f…

JavaScript性能優化實戰(10):前端框架性能優化深度解析

引言 React、Vue、Angular等框架雖然提供了強大的抽象和開發效率,但不恰當的使用方式會導致嚴重的性能問題,針對這些問題,本文將深入探討前端框架性能優化的核心技術和最佳實踐。 React性能優化核心技術 React通過虛擬DOM和高效的渲染機制提供了出色的性能,但當應用規模…

類和對象------2

目錄 一. C面向對象模型初探1 .成員變量和函數的存儲 二 this指針1 &#xff09;this指針工作原理2 &#xff09;this指針的使用3&#xff09; const修飾成員函數4 &#xff09;const修飾對象(常對象) 3.友元1 )友元語法2) 課堂練習 4 強化訓練(數組類封裝) 四 運算符重載&…

量子計算在金融科技中的應用前景

隨著量子計算技術的飛速發展&#xff0c;其在各行業的應用潛力逐漸顯現&#xff0c;金融科技領域更是備受關注。量子計算的強大計算能力有望為金融行業帶來前所未有的變革&#xff0c;從風險評估到投資組合優化&#xff0c;從高頻交易到加密技術&#xff0c;量子計算都可能成為…

Redisson 四大核心機制實現原理詳解

一、可重入鎖&#xff08;Reentrant Lock&#xff09; 可重入鎖是什么&#xff1f; 通俗定義 可重入鎖類似于一把“智能鎖”&#xff0c;它能識別當前的鎖持有者是否是當前線程&#xff1a; 如果是&#xff0c;則允許線程重復獲取鎖&#xff08;重入&#xff09;&#xff0c;并…

srs-7.0 支持obs推webrtc流

demo演示 官方教程: https://ossrs.net/lts/zh-cn/blog/Experience-Ultra-Low-Latency-Live-Streaming-with-OBS-WHIP 實現原理就是通過WHIP協議來傳輸 SDP信息 1、運行 ./objs/srs -c conf/rtc.conf 2、obs推流 3、web端播放webrtc流 打開web:ht

面試題——JDBC|Maven|Spring的IOC思想|DI思想|SpringMVC

目錄 一、JDBC 1、jdbc連接數據庫的基本步驟&#xff08;掌握**&#xff09; 2、Statement和PreparedStatement的區別 &#xff08;掌握***&#xff09; 二、Maven 1、maven的作用 2、maven 如何排除依賴 3、maven scope作用域有哪些&#xff1f; 三、Spring的IOC思想 …

從代碼學習數學優化算法 - 拉格朗日松弛 Python版

文章目錄 前言1. 問題定義 (Problem Definition)2. 拉格朗日松弛 (Lagrangian Relaxation)3. 拉格朗日對偶問題 (Lagrangian Dual)4. 次梯度優化 (Subgradient Optimization)5. Python 代碼實現導入庫和問題定義輔助函數:求解拉格朗日松弛子問題次梯度優化主循環結果展示與繪圖…

密碼學實驗

密碼學實驗二 一、實驗目的&#xff08;本次實驗所涉及并要求掌握的知識點&#xff09; 掌握RSA算法的基本原理并根據給出的RSA算法簡單的實現代碼源程序,以及能夠使用RSA對文件進行加密。掌握素性測試的基本原理&#xff0c;并且會使用Python進行簡單的素性測試以及初步理解…

力扣面試150題-- 從中序與后序遍歷序列構造二叉樹

Day 44 題目描述 思路 這題類似與昨天那題&#xff0c;首先來復習一下&#xff0c;后序遍歷&#xff0c;對于后序遍歷每一個元素都滿足以下規律&#xff1a; &#xff08;左子樹&#xff09;&#xff08;右子樹&#xff09;&#xff08;根&#xff09;&#xff0c;那么我們直…

2區組的2水平析因實驗的混區設計

本文是實驗設計與分析&#xff08;第6版&#xff0c;Montgomery著傅玨生譯)第7章2k析因的區組化和混區設計第7.4節的python解決方案。本文盡量避免重復書中的理論&#xff0c;著于提供python解決方案&#xff0c;并與原書的運算結果進行對比。您可以從Detail 下載實驗設計與分析…

反向傳播算法——矩陣形式遞推公式——ReLU傳遞函數

總結反向傳播算法。 來源于https://udlbook.github.io/udlbook/&#xff0c;我不明白初始不從 x 0 \boldsymbol{x}_0 x0?開始&#xff0c;而是從 z 0 \boldsymbol{z}_0 z0?開始&#xff0c;不知道怎么想的。 考慮一個深度神經網絡 g [ x i , ? ] g[\boldsymbol{x}_i, \bold…

2025年PMP 學習二十三 16章 高級項目管理

2025年PMP 學習二十三 16章 高級項目管理 文章目錄 2025年PMP 學習二十三 16章 高級項目管理高級項目管理戰略管理戰略管理的組成要素&#xff1a;企業戰略轉化為戰略行動的階段&#xff1a; 組織戰略類型戰略組織類型組織級項目管理OPM&#xff08;公司項目管理&#xff09; 組…

Journal of Real-Time Image Processing 投稿過程

投稿要求雙欄12頁以內(包括參考文獻)&#xff0c;這個排版要求感覺不是很嚴格&#xff0c;我當時就是用普通的雙欄的格式去拍的版&#xff0c;然后就提交了&#xff0c;也沒單獨去下載模版。 投稿過程 12.12 Submission received 12.12 Submission is under technical check 1…

t檢驗詳解:原理、類型與應用指南

t檢驗詳解&#xff1a;原理、類型與應用指南 t檢驗&#xff08;t-test&#xff09;是一種用于比較兩組數據均值是否存在顯著差異的統計方法&#xff0c;適用于數據近似正態分布且滿足方差齊性的場景。以下從核心原理、檢驗類型、實施步驟到實際應用進行系統解析。 一、t檢驗的…

Web4X·AI實業未來家庭普及產品矩陣

Web4XAI實業未來家庭普及產品矩陣 > 打造一個“AI能干活、人更自由”的超級生活系統&#xff08;web4-web4.0&#xff09; 一、AI生活服務類 1、代表產品&#xff1a; ? AI語音助手&#xff08;對話、提醒、天氣、家庭調度&#xff09; ? AI陪護機器人&#xff08;老…

Centos上搭建 OpenResty

一、OpenResty簡介 OpenResty 是基于 Nginx 的擴展平臺&#xff0c;完全兼容 Nginx 的核心功能&#xff08;如 HTTP 服務和反向代理&#xff09;&#xff0c;同時通過內嵌 LuaJIT 支持&#xff0c;允許開發者用 Lua 腳本靈活擴展業務邏輯。它簡化了動態邏輯的實現。 二、安裝…

項目管理進階:基于IPD流程的項目管理部分問題及建議書【附全文閱讀】

該文檔主要探討了研發項目管理中存在的問題及改進建議。指出項目組織、項目計劃、項目監控等方面存在的問題&#xff0c;并給出了相應的設計要點。建議建立跨部門、全流程的項目計劃體系&#xff0c;加強風險管理&#xff0c;引入科學的估計方法&#xff0c;建立項目歷史數據積…

JVM之GC常見的垃圾回收器

收集器適用區域特點適用場景Serial新生代單線程&#xff0c;STW&#xff08;Stop-The-World&#xff09;客戶端小應用Parallel Scavenge新生代多線程&#xff0c;吞吐量優先后臺計算任務ParNew新生代Serial 的多線程版配合 CMS 使用CMS老年代并發標記&#xff0c;低延遲響應優先…

免費私有化部署! PawSQL社區版,超越EverSQL的企業級SQL優化工具面向個人開發者開放使用了

1. 概覽 1.1 快速了解 PawSQL PawSQL是專注于數據庫性能優化的企業級工具&#xff0c;解決方案覆蓋SQL開發、測試、運維的整個流程&#xff0c;提供智能SQL審核、查詢重寫優化及自動化巡檢功能&#xff0c;支持MySQL、PostgreSQL、Oracle、SQL Server等主流數據庫及達夢、金倉…