1. 程式人生 > 其它 >第五章-C語言操作符

第五章-C語言操作符

一、 操作符分類

(1)算術操作符

+(加)-(減) *(乘) /(除) %(取模)

#include<stdio.h>
int main()
{
    //  / 操作符
    int a = 5 / 2;//如果兩個運算元都為整數,執行整數除法
    //商2餘1
    double a2 = 5 / 2.0;//有浮點數執行的就是浮點數除法
    // %操作符
    int b = 5 % 2;//兩個運算元必須為整數
    printf("a=%d\n", a);//a=2
    printf("a2=%lf\n", a2);//a=2.500000
    printf("b=%d\n", b);//b=1
return 0; }

(2) 移位操作符

<< 左移操作符

#include<stdio.h>
int main()
{
    int a = 16;//0000000010000,即2^4
    //>>--右移操作符
    //移動的是二進位制
    //算術右移--右丟棄,左補原位符號(通常使用)
    //邏輯右移--右丟棄,左補0
    int b=a >> 1;//8--2^3
    printf("%d\n", b);
    return 0;
}
#include<stdio.h>
int main()
{
    int a = -1
; //整數二進位制表述:原碼、反碼、補碼 //儲存在記憶體的是補碼 //原碼100000000000000000000000001 //反碼111111111111111111111111110 //補碼111111111111111111111111111 int b = a >> 1; printf("%d\n", b);//-1 return 0; }

>> 右移操作符

#include<stdio.h>
int main()
{
    int a =5;//101
    int b = a << 1;//1010=2^3+2=10
    //<<--左邊丟棄,右邊補零
printf("%d\n", b);//10 return 0; }

注:

移位操作符的運算元只能是整數。

對於移位運算子,不要移動負數位,這個是標準未定義的

(3)位操作符

& 按位與

#include<stdio.h>
int main()
{
    //& 按二進位制位與
    //兩個為1,則為1
    //一個為0,則為0
    int a = 3;//011
    int b = 5;//101
    int c = a & b;//001
    printf("%d\n", c);
    return 0;
}

| 按位或

#include<stdio.h>
int main()
{
    //| 按二進位制位或
    //兩個為0,則為0
    //一個為1,則為1
    int a = 3;//011
    int b = 5;//101
    int c = a |b;//111
    printf("%d\n", c);//7
    return 0;
}

^ 按位異或

#include<stdio.h>
int main()
{
    //^ 按位異或
    //相異為1
    //相同為0
    int a = 3;//011
    int b = 5;//101
    int c = a^b;//110
    printf("%d\n", c);//6
    return 0;
}

注:位操作符的運算元只能是整數。

//不能建立臨時變數(第三個變數)
//實現兩個數的交換。
#include <stdio.h>
int main()
{
    int a =3;//011
    int b =5;//101
    
    //建立臨時變數
    //int tmp = 0;
    //printf("before:a=%d\n b=%d\n", a, b);
    //tmp = a;
    //a = b;
    //a = tmp;
    //printf("after:a=%d\n b=%d\n", a, b);
    
    //加減法
    //缺陷:過於大,超出表達範圍,會丟失,可能會溢位
    //a = a + b;
    //b = a - b;
    //a = a - b;
    //printf("a = %d b = %d\n", a, b);

    //異或
    //不會溢位
    a = a ^ b;//110
    b = a ^ b;//011
    a = a ^ b;//101
    printf("a = %d b = %d\n", a, b);
    return 0;
}
//編寫程式碼實現
//求一個整數儲存在記憶體中的二進位制中1的個數
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    int num = 0;
    scanf("%d", &num);
    //統計num的補碼中有幾個1
    int count = 0;
    while (num)
    {
        if (num % 2 == 1)//餘數
            count++;
        num = num / 2;//去個位數
    }
    printf("二進位制中1的個數 = %d\n", count);
    return 0;
}
//優化,可以計算負數
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
    int num = 0;
    scanf("%d", &num);
    int i = 0;
    int count = 0;//計數
    for (i = 0; i < 32; i++)
    {
        //if (num & (1 <<i))
        if (1==((num >> i)&1))
        //32bit
        //num & 1==1即第一位為1
            count++;
    }
    printf("二進位制中1的個數 = %d\n", count);
    return 0;
}

(4) 賦值操作符

初始化:變數建立給一個值

賦值:變數有一個值,再給一個值

複合賦值符

+=( a = a + 2 / a + = 2 )

-= *= /= %=

>>= ( a >> = 1 / a = a >> 1)

<<= &= |= ^=

(5)單目操作符

只有一個運算元

! 邏輯反操作(假變成真,真變成假)

#include <stdio.h>
int main()
{
    int a = 0;
    if (a)
    {
        printf("xi\n");
    }
    if (!a)
    {
        printf("hehe\n");
    }
    return 0;
}

- 負值( a = - 5 / a = - a )

+ 正值

& 取地址(與指標搭配)

* 間接訪問操作符(解引用操作符)

#include <stdio.h>
int main()
{
    int a = 10;
    int* p = &a;
    *p = 20;
    return 0;
}

sizeof 運算元的型別長度(以位元組為單位)

為型別,不能去掉括號

#include <stdio.h>
int main()
{
    int a = 10;
    char c = 'r';
    char* p = &c;
    int arr[10] = { 0 };
    //記憶體所佔空間的大小,單位是位元組
    printf("%d\n", sizeof(a));//4(a為整型,佔4位元組
    printf("%d\n", sizeof(int));//4

    printf("%d\n", sizeof(c));//1(c為一個字元)
    printf("%d\n", sizeof(char));

    printf("%d\n", sizeof(p));//4(p為指標,4或8)
    printf("%d\n", sizeof(char*));

    printf("%d\n", sizeof(arr));//40(陣列為10個元素,每個元素四個位元組)
    printf("%d\n", sizeof(int [10]));
    return 0;
}
#include<stdio.h>
int main()
{
    short s = 0;
    int a = 10;
    printf("%d\n", sizeof(s = a + 5));//2 s是短整型
    printf("%d\n", s);//0 上面表示式不直接參與運算
    return 0;
}

~ 對一個數的二進位制按位取反

#include<stdio.h>
int main()
{
    int a = 11;//1011
    a = a | (1 << 2);
    printf("%d\n", a);//15
    a = a & (~(1 << 2));
    printf("%d\n", a);//11

    //int a = 0;
    //~按(二進位制)位取反
    //00000000000000000000000000000000
    //11111111111111111111111111111111--補碼
    //11111111111111111111111111111110--反碼
    //10000000000000000000000000000001--原碼
    //printf("%d\n", ~a);
    return 0;
}

-- 前置--(先--,後使用)、後置--(先使用,後--)

++ 前置++(先++,後使用)、後置++(先使用,後++)

(型別) 強制型別轉換 // int a = ( int ) 3.14 ;

(6)sizeof 和 陣列

#include <stdio.h>
void test1(int arr[])//指標接收
{
    printf("%d\n", sizeof(arr));//4
}
void test2(char ch[])
{
    printf("%d\n", sizeof(ch));//4
}
int main()
{
    int arr[10] = { 0 };
    char ch[10] = { 0 };
    printf("%d\n", sizeof(arr));//40--1個整型4個位元組,10*4=40
    printf("%d\n", sizeof(ch));//10
    test1(arr);//傳遞是首元素地址
    test2(ch);
    return 0;
}

(7)關係操作符

>大於

>=大於等於

<小於

<=小於等於

!= 用於測試“不相等”

== 用於測試“相等”

(8)邏輯操作符

&& 邏輯與(都為真,則為1;一個假,則為0)

|| 邏輯或(都為假,則為0;一個真,則為1)

#include <stdio.h>
int main()
{
    int a = 0;
    int b = 5;
    int c = a && b;
    int d = a || b;
    printf("%d\n", c);//0
    printf("%d\n", d);//1
    return 0;
}
#include <stdio.h>
int main()
{
    //int i = 0, a = 0, b = 2, c = 3, d = 4;
    //i = a++ && ++b && d++;//1 2 3 4 
    //a先使用,後++
    //由於左邊為假,右邊不再計算
    int i = 0, a = 1, b = 2, c = 3, d = 4;
    i = a++||++b||d++;//2 2 3 4
    //a=1,即為真,後面不用計算
    printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
    return 0;
}

(9) 條件操作符

exp1 ? exp2 : exp3

表示式1為真,即表示式2為結果

表示式1為假,即表示式3為結果

#include <stdio.h>
int main()
{
    int a = 0;
    int b = 0;
    /*if (a > 5)
        b = 3;
    else
        b = -3;

    b = (a > 5 ? 3 : -3);*/
    int max = 0;
    if (a > b)
        max = a;
    else
        max = b;

    max = (a > b ? a : b);
    return 0;
}

(10)逗號表示式

逗號表示式,就是用逗號隔開的多個表示式。

逗號表示式,從左向右依次執行。整個表示式的結果是最後一個表示式的結果。

int a = 1;
    int b = 2;
    int c = (a > b, a = b + 10, a, b = a + 1);
           //無結果,12=2+10;12;13=12+1
    printf("%d\n", c);//13

    if (a = b + 1, c = a / 2, d > 0)
        //判斷d是否大於0,大於0,前面為真,否則為假

    a = get_val();//函式放於a中
    count_val(a);
    while (a > 0)
    {
        //業務處理
        a = get_val();
        count_val(a);
    }
    //優化
    while (a = get_val(), count_val(a), a > 0)
    {
        //業務處理
    }

(11) 下標引用、函式呼叫和結構成員

1. [ ] 下標引用操作符

運算元:一個數組名 + 一個索引值

#include<stdio.h>
int main()
{
    int arr[10] = { 0 };//建立陣列
    arr[4] = 10;//實用下標引用操作符
    return 0;
}

2.( ) 函式呼叫操作符

#include <stdio.h>
int get_max(int x, int y)
//這個括號不是函式呼叫操作符
{
    return x > y ? x : y;
}
int main()
{
    int a = 10;
    int b = 20;
    int max = get_max(a, b);
    //呼叫函式的時候的()就是函式呼叫操作符
       //運算元為a,b,get_max,有三個
    printf("max=%d\n", max);
    return 0;
}

3. 訪問一個結構的成員

. 結構體.成員名

-> 結構體指標->成員名

#include <stdio.h>
//型別:結構體型別
struct Stu
{
    //成員變數
    char name[10];
    int age;
    char id[20];
    double score;
};
int main()
{
    //使用strut Stu的型別建立一個學生物件s1,並初始化
    struct Stu s1 = {"",20,"201851520"};
    struct Stu* ps = &s1;
    printf("%s\n",ps->name);
    printf("%d\n", ps->age);
    /*printf("%d\n", (*ps).name);
    printf("%s\n", s1.name);
    printf("%d\n", s1.age);
    printf("%s\n", s1.id);*/
    return 0;
}

二、表示式求值

表示式求值的順序一部分是由操作符的優先順序和結合性決定。

同樣,有些表示式的運算元在求值的過程中可能需要轉換為其他型別

(1)隱式型別轉換

整型提升:C的整型算術運算總是至少以預設整型型別的精度來進行的。為了獲得這個精度,表示式中的字元和短整型運算元在使用之前被轉換為普通整型。

如何進行整體提升呢? 整形提升是按照變數的資料型別的符號位來提升的

#include <stdio.h>
int main()
{
    char a = 3;
    //a中存放00000011
    //提升加0
    char b = 127;
    //b中存放01111111
    char c = a + b;
    //c=a+b=10000010
    //補碼111111...11110000010
    //反碼111111...11110000001(減一)
    //原碼100000...00001111110(取反)
    printf("%d\n", c);//-126
    //%d,即列印整型
    return 0;
}
#include<stdio.h>
int main()
{
    //定義
    char a = 0xb6;//char 1位元組
    //b6,b=10,兩個十六進位制的數,二進位制為10110110
    
    short b = 0xb600;//short 2位元組
    int c = 0xb6000000;//int 4位元組
    if (a == 0xb6)//會補1
        printf("a");
    if (b == 0xb600)
        printf("b");
    if (c == 0xb6000000)
        printf("c");//c
    return 0;
}
#include<stdio.h>
int main()
{
    char c = 1;//char是1位元組
    printf("%u\n", sizeof(c));//1
    printf("%u\n", sizeof(+c));//4
    printf("%u\n", sizeof(-c));//4
    //整型提升,即計算的整型大小
    printf("%u\n", sizeof(!c));//1
    return 0;
}

(2)算術轉換

個操作符的各個運算元屬於不同的型別,將其中一個運算元的轉換為另一個運算元的型別

long double 8位元組

double 8位元組

float 4位元組

unsigned longint 4位元組

longint 4位元組

unsigned int 4位元組

int 4位元組

上面這個列表中排名較低,那麼首先要轉換為另外一個運算元的型別後執行運 算

(3)操作符的屬性

複雜表示式的求值有三個影響的因素

1. 操作符的優先順序

2. 操作符的結合性

3. 是否控制求值順序(是否繼續運算)

#include<stdio.h>
int main()
{
    int a = 10;
    int b = 20;
    int c = b + a * 3;
    //操作符的優先順序
    //+和=優先順序相同,比*優先順序低
    int d = a + b + c;
    //優先順序一致
    //操作符的結合性
    return 0;
}

問題表示式

a*b + c*d + e*f;

計算順序,不知道最先開始哪個,沒有唯一計算路徑

c + --c ;

--優先順序比+高,+操作符的左運算元c的值,可能是--c後,也可能是--c前獲取,是有歧義的。

ret = (++i) + (++i) + (++i) ;

answer = fun() - fun() * fun() ;