Stories

Detail Return Return

C語言:位運算、分支、循環 - Stories Detail

位運算、分支、循環

一、基礎語法

1.1 位運算符

運算符 術語 示例 結果
& 按位與 011 & 101 2個都為1才為1,結果為001
\ 按位或 011 \ 101 有1個為1就為1,結果為111
^ 按位異或 011 ^ 101 不同的為1,結果為110
~ 取反 0000 0011 1111 1100
<< 左移 1010 << 1 10100
>> 右移 1010 >> 1 0101
#include <stdio.h>
#include <stdint.h>
int main() {
    uint8_t a=0b011;
    uint8_t b=0b101;
    printf("a & b = %#x\n",a&b);
    printf("a | b = %#x\n",a|b);
    printf("a ^ b = %#x\n",a^b);
    printf("a  = %#x\n",(uint8_t)~a);
    uint8_t c=0b1010;
    printf("c<<1 = %#x\n",c << 1);//00010100
    printf("c<<2 = %#x\n",c << 2);//00101000
    printf("c>>1 = %#x\n",c >> 1);//00000101
    printf("c>>2 = %#x\n",c >> 2);//00000010
    return 0;
}

小公式

操作需求 表達式 説明
第 n 位置 0 temp & ~(1 << n) 僅將第 n 位設為 0,其餘位保持不變
第 n 位置 1 temp I (1 << n) 僅將第 n 位設為 1,其餘位保持不變(表達式本身不改變temp,需賦值才改變 )
第 n 位取反 temp ^ (1 << n) 僅將第 n 位按位取反,其餘位保持不變
取出第 n 位 (temp & (1 << n)) >> n 或 (temp >> n) & 1 獲取第 n 位的值(0 或 1)

案例:

#include <stdio.h>
#include <stdint.h>
int main()
{
    // 將變量a的第2位設置為1,其他位保持不變
    uint8_t a = 0b10110011;
    printf("%0#x\n", a | (1 >> 2));

    // 將變量b的第2位、第6位設置為1,其他位保持不變
    uint8_t b = 0b10110011; // 0xb3;
    printf("%0#x\n", b | (1 >> 2) | (1 << 6));

    // 將變量c的第5位設置為0,其他位保持不變
    uint8_t c = 0b10110011; // 0xb3;
    printf("%0#x\n",c & ~(1 << 5));

    // 將變量d的第0~3位設置為0,其他位保持不變
    uint8_t d = 0b11111111; // 0xff;
    printf("%0#x\n",d & 0xf0);
    
    // 將變量e的第2位取反,其他位保持不變
    uint8_t e = 0b10110011; // 0xb3;
    printf("%0#x\n",e^(1<<2));

    // 將變量f取出8-15位
    uint32_t f = 0x12345678;
    printf("%0#x\n",(f>>8) & 0x0000ff);//0001 0010 0011 0100 0101 0110 0111 1001
    return 0;                          //0000 0000 0000 0000 0000 0000 1111 1111
} 

練習

#include <stdio.h>
#include <stdint.h>
int main() {
// 將變量a的第1位設置為1,其他位保持不變
uint8_t a = 0b10101001;  // 0xa9   1010 1001
//printf("%#x\n",a|(1<<1));// 0xab   1010 1011

// 將變量b的第3位設置為0,其他位保持不變
uint8_t b = 0b10101001;  // 0xa9   1010 1001
//printf("%#x\n",b&~(1<<3));//0xa1   1010 0001

// 將變量c的第7位取反,其他位保持不變
uint8_t c = 0b10101001;  // 0xa9   1010 1001
//printf("%#x\n",c^(1<<7));// 0x29   0010 1001

// 將變量d的第0位和第7位取反
uint8_t d = 0b10110011;  // 0xb3;  1011 0011
//printf("%#x\n",d^1^(1<<7));//0x32  0011 0010

// 檢查變量e的第7位是否為1,如果是則輸出"Bit is set",否則輸出"Bit is not set"。
uint8_t e = 0b10110011; 
/*if((e>>7)==1){
    printf("Bit is set\n");
}else{
    printf("Bit is not set\n");
}
    return 0;
}*/

1.2 類型轉換

類型轉換的原則:

  • 佔用內存字節數少(值域小)的類型,向佔用內存字節數多(值域大)的類型轉換,以保證精度不降低。
#include <stdio.h>

int main() {

    char num1=100;
    int num2=(int)num1;//類型轉換格式為  (轉換後的類型)轉換的數
                      //比如(int)num1  num1是char類型,轉換為int類型
    printf("num2=%d\n",num2);
//由於int比char取值範圍大,所以可以正常輸出結果
    num2=200;
    num1=(char)num2;
    printf("num1=%d\n",num1);
//輸出-56  char取值範圍為(-128~127),數據溢出遵循 “模 2ⁿ” 規則(n 為位數,此處 n=8,2ⁿ=256)
//當賦值大於最大值(127)時,結果 = 賦值 - 256,代入計算:200 - 256 = -56
    return 0;
}

二、分支

2.1 if 語句

#include <stdio.h>

int main() {
    int age;
    printf("請輸入你的年齡:");
    scanf("%d",&age);

//if格式
    if(age>=18)//括號裏面是條件
    {
        printf("你可以進網吧玩遊戲了\n");
    }

2.2 if...else 語句

#include <stdio.h>

int main() {
    int age;
    printf("請輸入你的年齡:");
    scanf("%d",&age);

//if.....else 格式
    if(age>=18)//括號裏面是條件
    {
        printf("你可以進網吧玩遊戲了\n");//滿足條件後運行的程序
    }
    else//反之的意思,如果不滿足上面條件就會運行下面內容
    {
        printf("小朋友不準玩遊戲哦");
    }

    return 0;
}

if括號裏面條件,如果滿足條件就會運行if裏面程序,如果不滿足就會運行else裏面**的程序

2.3 三目運算符

#include <stdio.h>

int main() {
    int a = 10, b = 20;
    int max;
    
    //格式為   表達式1 ? 表達式2 : 表達式3;
    max = (a > b) ? a : b;
    printf("最大值是:%d\n", max);  // 輸出:20
    
    // 等效的if-else語句
    if (a > b) {
        max = a;
    } else {
        max = b;
    }
    
    return 0;
}

用於根據表達式1的結果(真或假)來選擇執行表達式2或表達式3,相當於簡化的if-else語句。
表達式1的結果為 “真”(非 0 值),則整個三目表達式的值等於表達式2的值
表達式1的結果為 “假”(0 值),則整個三目表達式的值等於表達式3的值

2.4 if…else if…else語句


● 天貓超市雙 11 推出以下優惠促銷活動:
  ○ 購物滿 50 元,打 9 折;
  ○ 購物滿 100 元,打 8 折;
  ○ 購物滿 200 元,打 7 折;
  ○ 購物滿 300 元,打 6 折;
● 編程計算當購物滿 s 元時,實際付費多少?



if (條件1) {
    滿足條件1執行的代碼
} else if (條件2) { // 條件1,不滿足,才會判斷條件2
    滿足條件2執行的代碼
} else if (條件3) { // 上面條件不滿足,才會判斷條件3
    滿足條件3執行的代碼
} else {
    上面條件都不滿足,才到else
}
1. 從上往下判斷
2. 只要有1個滿足條件,執行對應的代碼塊,後面的代碼不會再判斷執行

● 天貓超市雙 11 推出以下優惠促銷活動:
           沒有打折    打折
    double money, real_money;
  ○ 購物滿 50 元,打 9 折;  money >= 50  && money < 100     real_money = 0.9 * money
  ○ 購物滿 100 元,打 8 折; money >= 100  && money < 200     real_money = 0.8 * money
  ○ 購物滿 200 元,打 7 折; money >= 200  && money < 300     real_money = 0.7 * money
  ○ 購物滿 300 元,打 6 折; money >= 300                     real_money = 0.6 * money
                           else                             real_money = money
● 編程計算當購物滿 s 元時,實際付費多少?

○ 購物滿 300 元,打 6 折; money >= 300     real_money = 0.6 * money
○ 購物滿 200 元,打 7 折; money >= 200     real_money = 0.7 * money
○ 購物滿 100 元,打 8 折; money >= 100     real_money = 0.8 * money
○ 購物滿 50 元,打 9 折;  money >= 50      real_money = 0.9 * money
                           else           real_money = money

2.5 switch語句

  • switch可以支持數據類型:int、枚舉類型、char類型
  • switch和if區別:

    • 需要根據布爾條件來執行不同的代碼塊,則應使用if語句
    • 需要根據表達式的值來執行不同的代碼塊,則應使用switch語句

基本格式

switch (表達式) {
    case 常量1:
        // 當表達式的值等於常量1時執行的語句
        break;  // 跳出switch結構
    case 常量2:
        // 當表達式的值等於常量2時執行的語句
        break;
    // ... 更多case分支
    default:
        // 當表達式的值與所有case常量都不匹配時執行的語句
        break;  // 可選(最後一個分支可省略)
}
  • 各部分作用

    • 表達式

      • 必須是整數類型(int、char、enum等),不能是浮點數或字符串。其值將與各case後的常量比較。
    • case 常量

      • case後必須跟常量表達式(如5、'a'、枚舉值),不能是變量。

      多個case不能使用相同的常量(否則編譯報錯)。

    • break 語句

      • 用於跳出switch結構,防止執行完當前case後繼續執行後續case(稱為 “穿透”)。
      • 若省略break,程序會依次執行下一個case的語句,直到遇到break或switch結束。

        • default 分支
        • 可選分支,當表達式的值與所有case常量都不匹配時執行。

        通常放在所有case之後,也可省略(此時不匹配時無任何操作)。

示例

#include <stdio.h>

int main() {
    char grade = 'B';
    switch (grade) {
        case 'A':
            printf("優秀\n");
            break;
        case 'B':
            printf("良好\n");  // 執行此分支
            break;
        case 'C':
            printf("及格\n");
            break;
        default:
            printf("不及格\n");
    }
    return 0;
}
// 輸出:良好

2.6 分支綜合案例


需求:
1. 輸入:年份(整數)和月份(整數)
2. 輸出:該月份的天數(整數)
思路:
1. 定義變量保存年份、月份、天數
2. 輸入年份和月份
3. 根據月份輸出天數
  - 1、3、5、7、8、10、12月  31天
  - 4、6、9、11月            30天
  - 2月     非閏年 28天  閏年 29天
  閏年判斷:能被4整除,但不能被100整除的;或者能被400整除的年份

答案

#include <stdio.h>
int main()
{
    int year, month, day;
    printf("請輸入年份和月份:");
    scanf("%d,%d", &year, &month);
    switch (month)
    {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        day = 31;
        break;
    case 4:
    case 6:
    case 9:
    case 11:
        day = 30;
        break;
    case 2:
        if ((year % 4 == 0 && year % 100 == 0) || (year % 400 != 0))
        {
            day = 29;
        }
        else
        {
            day = 28;
        }
        break;
    default:
        printf("輸入錯誤\n");
        break;
    }
    printf("%d年%d月有%d天\n", year, month, day);
    return 0;
}

三、循環

3.1 while語句

基本格式

while (循環條件) {
    // 循環體:當條件為真時執行的語句塊
}

執行邏輯

  • 判斷條件:首先檢查循環條件(一個返回布爾值的表達式,非 0 為真,0 為假)。
  • 執行循環體:若條件為真,執行{}中的循環體語句;若為假,跳出循環,執行後續代碼。
  • 重複過程:循環體執行完畢後,再次返回步驟 1 判斷條件,直到條件為假時結束循環。
#include <stdio.h>

int main() {
    int i=0;
    while(i<5)
    {
        printf("跑的第%d圈\n",i);
        i++;
    }
    printf("跳出循環是第%d圈\n",i);
    return 0;
}

3.2 do...while語句

do {
    // 循環體:至少執行一次的語句塊
} while (循環條件);  // 注意末尾有分號

執行邏輯

  • 執行循環體:首先無條件執行一次{}中的循環體語句。
  • 判斷條件:檢查循環條件(非 0 為真,0 為假)。
  • 決定是否重複:若條件為真,返回步驟 1 再次執行循環體;若為假,跳出循環,執行後續代碼。
#include <stdio.h>

int main()
{
    int i = 0;
    do
    {
        printf("跑步第%d圈\n", i);
        i++;
    } while (i < 5);
    printf("跳出循環第%d圈\n",i);//會至少循環一次

    return 0;
}

3.3 for語句

在 C 語言中,for語句是一種功能強大的循環控制結構,特別適合循環次數已知或可預先計算的場景,其語法結構比while更緊湊。

語法格式:

for (初始化表達式; 循環條件; 更新表達式) {
    // 循環體:條件為真時執行的語句塊
}

各部分作用

  • 初始化表達式:循環開始前執行一次,通常用於初始化循環變量(如int i = 0)
  • 循環條件:每次執行循環體前判斷,非 0 為真(繼續循環),0 為假(退出循環)
  • 更新表達式:每次循環體執行後執行,通常用於修改循環變量(如i++)
初始化 → 判斷條件 → 條件為真 → 執行循環體 → 更新表達式 → 再次-------------------------------------- ↓----------------------------------------------判斷...
------------------------------------ ↓-------------------------------------------------------
           ------------------------------條件為假 → 退出循環-----------------------------------


基本用法(輸出 1~5)

#include <stdio.h>

int main() {
    int i;
    for(i=0;i<5;i++)
    {
    printf("跑的第%i圈\n",i);  
    }
    printf("跳出循環是第%d圈\n",i);
    return 0;
}

省略部分表達式

// 省略初始化(在外部定義變量)
int i = 0;
for (; i < 3; i++) {
    printf("%d ", i);  // 輸出:0 1 2
}

// 省略條件(無限循環)
for (int j = 0; ; j++) {
    if (j >= 2) break;
    printf("%d ", j);  // 輸出:0 1
}

// 省略更新(在循環體內更新)
for (int k = 0; k < 3; ) {
    printf("%d ", k);
    k++;  // 輸出:0 1 2
}

3.4 循環嵌套

在 C 語言中,循環嵌套指的是在一個循環(外層循環)的循環體內包含另一個循環(內層循環)。這種結構用於處理需要多層重複的邏輯,例如二維數組遍歷、矩陣操作、圖形打印等。
基本結構

// 外層循環
for (初始化1; 條件1; 更新1) {
    // 內層循環(被外層循環包含)
    for (初始化2; 條件2; 更新2) {
        // 循環體:內層循環的執行語句
    }
    // 外層循環的其他語句
}

執行邏輯

  • 外層循環執行一次,內層循環會完整執行所有次數
  • 內層循環執行完畢後,外層循環才會進入下一次迭代
  • 總執行次數 = 外層循環次數 × 內層循環次數

通過for循環嵌套打印內容:  i行 j列
* * * * * 
* * * * * 
* * * * *  
説明:
1)每行有5個*,總共有3行  3行5列
2)*之間有空格隔開
3)printf()1次只能打印1個*

答案

#include <stdio.h>

int main() {
    for(int j=1;j<=3;j++){
       for(int i=1;i<=5;i++){
        printf("* ");
    }
    printf("\n"); 
    }
    return 0;
}

3.5 死循環

在 C 語言中,死循環(Infinite Loop)指的是條件始終為真、無法自行結束的循環結構。死循環本身並非總是錯誤,在某些場景下(如服務器程序、實時監控系統)是有意設計的,但多數情況下是邏輯錯誤導致的。
基本格式

// 條件恆為真(非0值均為真)
while (1) {
    // 循環體
}

// 條件變量未更新,始終為真
int flag = 1;
while (flag) {  // flag始終為1,循環永不結束
    printf("死循環中...\n");
    // 缺少flag = 0的終止條件
}

3.6 循環案例:1到100累加和

#include <stdio.h>

int main() {
    int j=0;
    for(int i=1;i<=100;i++){
      j+=i;
    }
    printf("1加到100的值為:%d\n",j); 
    return 0;
}

四、跳轉關鍵字

  • 循環和switch專屬的跳轉:break
  • 循環專屬的跳轉:continue
  • 無條件跳轉:goto

4.1 break

  • 循環中break,某一條件滿足時,不再執行循環體中後續重複的代碼,並退出循環
  • 作用:跳出當前所在的循環(for/while/do...while)或switch語句。
  • 特點:僅跳出最內層的結構,不影響外層。
#include <stdio.h>

int main()
{
    int i;
    for (i = 1; i <= 5; i++)
    {
        if (i == 3)
        {
            printf("第%i圈太累了,不跑了\n", i);
            break;
        }

        printf("跑的第%i圈\n", i);
    }
    return 0;
}

4.2 continue

  • 某一條件滿足時,不再執行本次循環體中後續重複的代碼,但進入下一次循環判斷
  • 作用:跳過當前循環體中剩餘的語句,直接進入下一次循環。
  • 特點:僅影響當前循環的一次迭代,不終止整個循環。
#include <stdio.h>

int main()
{
    int i;
    for (i = 1; i <= 5; i++)
    {
        if (i == 3)
        {
            printf("第%i圈太累了,不跑了\n", i);
            continue;
        }

        printf("跑的第%i圈\n", i);
    }
    return 0;
}

可以對三個進行對比

4.3 goto

  • goto用於無條件跳轉,儘量少用
  • 在一種情況下可使用goto語句:從一組嵌套的循環中跳出
  • 作用:無條件跳轉到同一函數內的標記位置(需自定義標記)。
  • 特點:可以跨越多層結構跳轉,但過度使用會導致代碼邏輯混亂(俗稱 “spaghetti code”)。
#include <stdio.h>

int main() {
    int num = 0;
    loop_start:  // 自定義標記(格式:標記名:)
        printf("請輸入一個正數:");
        scanf("%d", &num);
        
        if (num <= 0) {
            printf("輸入錯誤,請重新輸入!\n");
            goto loop_start;  // 跳轉到標記處,重新執行
        }
        
        printf("你輸入的正數是:%d\n", num);
    return 0;
}

對比總結

關鍵字 跳轉範圍 典型場景
break 跳出當前循環或switch 提前終止循環、結束case分支
continue 跳過本次循環剩餘部分 過濾不符合條件的迭代
goto 跳轉到同一函數內的標記 多層循環跳出、統一錯誤處理

注意事項

  • break和continue僅能用於循環或switch結構中。
  • goto不能跨函數跳轉,也不建議在普通邏輯中頻繁使用(會降低代碼可讀性)。
  • 合理使用跳轉關鍵字可以簡化邏輯,但過度依
    賴會導致代碼難以維護。
user avatar u_16985197 Avatar huizhudev Avatar patsy324df_banks901rn Avatar chaoqiezi Avatar selectdb Avatar wuyujingcha Avatar idiomeo Avatar leeqvip Avatar meirenlideshuizhurou Avatar xiaoyuindebuilder Avatar shumile_5f6954c414184 Avatar ansurfen Avatar
Favorites 13 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.