C 語言 運算符 全網最全整理

C 語言 運算符 全網最全整理

碼字不易,對你有幫助 點贊/轉發/關注 支持一下作者

微信搜公衆號:不會編程的程序圓

看更多幹貨,獲取第一時間更新

思維導圖


目錄


正文


一 算數操作符

+

-

*

/

%: % 左右兩邊的數必須都爲整數

二 移位操作符

>> : 右移

<<: 左移

例1:b = 20

例2:b = -4

img

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-APrIn3AF-1585038906075)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]

注意1:

左移直接在空的地方補0 如例1

右移有兩種情況:

1.邏輯位移 補0

2.算數位移 補1 如例2(一般都是這種情況)

注意2:

移位操作符,不要移動負數位,這是標準未定義。

如:num >> -1//error

三 位操作符

& (按位與) | (按位或) ^(按位異或)

例3:按位與

img

例4:按位或

img

例5:按位異或

img

例6:異或的應用——交換兩個值的內容

方法1:

int a,b,c;
c = a;
a = b;
b = c;

方法2:(如果a,b很大可能會溢出)

int a,b;
a = a + b;
b = a - b;
a = a - b;

方法3(異或法):

int a, b;
a = a^b;
b = a^b;
a = a^b;

例7:怎麼求一個二進制位中1的個數

#include<stdio.h>
int CountOneBit(unsigned int n){//解決負數無法計算問題,這種運算運算的是補碼
  int count = 0;
  while(n){//類比十進制中每位數的求法
    if(n%2 == 1)
      count++;
    n/=2;
  }
  return count;
}
int main(){
  int n = 0;
  int num_1 = 0;
  printf("請輸入一個數:");
  scanf("%d",&n);
  num_1 = CountOneBit(n);
  printf("%d的二進制序列中有%d個 1",n,num_1);
}

unsigned的作用:

unsigned就是將這個二進制數最高位的符號位變成計數位。下面我們舉個例子幫大家理解一下

如果我們輸入的是-1

-1%2 == -1

-1/2 = 0

這樣輸出的count爲0

但是我們知道-1的補碼是11111111111111111111111111111111

這樣我們的代碼就侷限在正整數

如果加上unsigned 雖然我們輸入的是-1 但是程序計算是是按照 unsigned int 的最大值,這樣就避免了這個問題

更多位運算相關示例: https://github.com/hairrrrr/linux.ccode/tree/master/Bit/ClassCode/2020-1-7%EF%BC%888%EF%BC%89

四 賦值操作符

=

a = b = c

它的意義是將c的值賦給b,再將b的值賦給a。其實這樣理解不夠準確,其實應該這麼寫:

a = (b = c)

先將c的值賦給b 然後將這個整體,即b的值賦給a

五 複合賦值符

+= -= *= \= %= >>= <<= &= |= ^=

六 單目操作符

\-

=

&(取地址)

sizeof(操作數的類型長度)

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

-- ++(前置,後置)

* (解引用)

(類型)(強制類型轉換)

例8:!的應用

應用!與flag來判斷情況做出選擇

if(flag){

flag爲真進入循環;

}

if(!flag){

flag爲假進入循環;

}

printf函數打印格式

%#p 0XCCCCCC

%p 00CCCCCCC

%x cccccc

%X CCCCCC

1

int a = 0; 

sizeof(a)=4

sizeof(int) = 4

sizeof a    √

sizeof int   ×

2

sizeof求數組大小    sizeof(arr)

sizeof求數組元素個數  sizeof(arr)/sizeof(arr[0])

切記!!!sizeof不能再函數內部求指針數組的大小

3

int  a = 10;

short s =3;

printf('%d\n",sizeof(s = a+4));

printf("%d\n",a);

printf("%d\n",s);

輸出: 2     10      3

賦值並不會將類型一同賦予左值

sizeof在編譯階段就已經運行結束了(sizeof 被 換成 2)

而s = a + 4要到生成可執行文件之後纔會完成

編譯(.c) -- 鏈接(.exe)

4  

小心細節問題。進入函數後 ch實際上變成了指針變量。

img

例9:~ 的應用

若想完成一下操作:

15      00001111

將從右數第4位變成0 ,應該如何操作?

a = (1<<4-1)     00001000

b = ~(a)            11110111

b&15                00000111

所以可以這麼寫:

a &=~(1<<4-1));

如何變回來呢?

00001000   1<<4-1

00000111 |  (1<<4-1) 即可

七 關係操作符

>

>=

<=

!=

==

注意:不要將 ‘ == ’ 寫成 ‘ = ’

八 邏輯操作符

&&

||

例11 &與&&的差異:

img
例12 這個題值得思考

img

在&&的判斷中如果一邊位假(0)那麼程序就會停止向後面判斷。所以++b與d++並沒有執行

在 || 的判斷中如果一邊爲真,則停止繼續向下判斷。(如:++a || b++ || c)

補充:

img

img

img

九 條件操作符

a > b ? a : b

十 逗號表達式

a,b,c,d,.....n

逗號表達式整體的值等於最後一個表達式的值

例13 思考題

int main() {
	int a = 0; 
	int b = 1, c = 2;
	a = (a = b, b += c, c--);
	printf("case1:%d\n", a);

	a = 0,b = 1, c = 2;
	a = (a < 0, a++, b = a);
	printf("case2:%d\n", a);

	a = 0, b = 1, c = 2;
	a = (a<0, b<a);
	printf("case3:%d\n", a);

	a = 0, b = 1, c = 2;
	if (a = b + 1, c = a / 2 - 1, c == 0)
		printf("case4:%d\n", c);
	}

img
另一種代碼書寫方式:

	//一般情況
	a = get_val();
	count_val(a);
	while (a > 0) {
		//業務處理
		a = get_val();
		count_val(a);
	}
	//應用逗號表達式
	while (a = get_val(), count_val(a), a > 0) {
		//業務處理
	}

合理應用逗號表達式可以簡化代碼。

11 其他

1. [] 下標引用操作符

對於數組 arr[5] = {1,2,3,4,5}

我們一般的用法是:

arr[0],arr[1],arr[2]…其中arr[0]就代表訪問數組中第一個元素,arr[1]代表訪問第二個以此類推

學習了指針之後我們知道:

arr代表數組首元素的地址。

arr[0],arr[1],arr[2]…我們可以改寫成:arr,(arr+1),*(arr+2)… (arr可以理解爲(arr+0))

進一步思考:

(arr+1)可以改寫成(1+arr)

那麼arr[1]可否寫成1[arr]呢?答案是肯定的。

所以我們就有了一下結論:

1[arr] == arr[1] == *(arr+1) == *(1+arr)

事實上,無論哪一種寫法,程序再最終編譯的時候都會轉化爲:*( arr+1)

2. ( ) 函數調用操作符

例14.有參數調用

int add(int x, int y){
    return x+y;
}    
int main(){
    int a = 1;
    int b = 2;
    printf("%d",add(a,b));
}    

例15.無參數調用

void test(){
    printf("看到這裏的都是人才!!!\n");
}
int main(){
    test();
}

3.訪問一個結構的成員

. (結構體.成員名)

-> (結構體指針 -> 成員名)

例16.

struct Stu{
    char name[20];
    int age;
}stu;
int main(){
    stu = {"張三",20};
    struct Stu *ps = &stu;
    //下面三種寫法都是正確的
    printf("%s  %d\n",stu.name,stu.age);
    printf("%s  %d\n",(*ps).name,(*ps).age);
    printf("%s  %d\n",ps->name,ps->age);
}

12 表達式求值

1. 隱式類型轉換

  • C的整型算術運算總是至少以缺省整型類型的精度來進行的。
  • 爲了獲得這個精度,表達式中的字符和短整型操作數在使用之前被轉換爲普通整型,這種轉換稱爲整型提升

整型提升的意義:
表達式的整型運算要在CPU的相應運算器件內執行,CPU內整型運算器(ALU)的操作數的字節長度 一般就是int的字節長度,同時也是CPU的通用寄存器的長度。
因此,即使兩個char類型的相加,在CPU執行時實際上也要先轉換爲CPU內整型操作數的標準長 度。
通用CPU(general-purpose CPU)是難以直接實現兩個8比特字節直接相加運算(雖然機器指令 中可能有這種字節相加指令)。所以,表達式中各種長度可能小於int長度的整型值,都必須先轉 換爲int或unsigned int,然後才能送入CPU去執行運算。


整型提升方法:

正數的整型高位補充0 負數補充1

例17.整型提升示例

注:char是有符號的

img

補充:字符類型的反碼(1字節)及其表示的值

img

總結:

char 的值範圍是:-128 ~ 127

unsigned char 值的範圍是:0 ~ 255

例18.整型提升在程序中的證明

int main()
{
	char a = 0x41;
	char b = 0xFF;//0xFF -> 255  11111111
	int c = 0xb6000000;
	if (a == 0x41) {//正數原碼補碼一致,整型提升補碼不變
		printf("a\n");
		printf("%d %c\n", a, a);
	}
	if (b == 0xFF) {
		printf("b\n");
	}
	//在判斷 b==0xFF 時 要對b進行整型提升
	//b  11111111  ->   11111111  11111111  11111111  11111111  而 0xEF的補碼依然是11111111 所以這兩個補碼時不同的
	printf("%d %c\n", b, b);
	//輸出時 依然要對b進行整型提升 
	// 11111111 -> 補碼:11111111  11111111  11111111  11111111 
	//反碼:11111111  11111111  11111111  11111110
	//原碼:10000000  00000000  00000000  00000001  即:-1
	if(c==0xb6000000)
		printf("c\n");
	return 0;
}

例子20.整型提升的再一次證明

img

2. 算數轉換

如果某個操作符的各個操作數屬於不同的類型,那麼除非其中一個操作數的轉換爲另一個操作數的類 型,否則操作就無法進行。下面的層次體系稱爲尋常算術轉換。


long double 8byte

double 8byte

float 4byte

unsigned long int 4byte

long int 4byte

unsigned int 4byte

int 4byte


如果某個操作數的類型在上面這個列表中排名較低,那麼首先要轉換爲另外一個操作數的類型後執行運算

附:各類型變量在內存中佔的字節(32位)

int main() {
	printf("%d\n", sizeof(char));//1
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof(unsigned int));//4
	printf("%d\n", sizeof(long));//4
	printf("%d\n", sizeof(unsigned long));//4
	printf("%d\n", sizeof(long long int));//8
	printf("%d\n", sizeof(float));//4
	printf("%d\n", sizeof(double));//8
	printf("%d\n", sizeof(long double));//8
}

3. 操作符屬性

  1. 操作符的優先級

  2. 操作符的結合性

  3. 是否控制求值順序


在 Github 上看更全的文章目錄:

https://github.com/hairrrrr/C-CrashCourse

這個系列文章的代碼都會上傳上去,歡迎 star


以上就是本次的內容。

如果文章有錯誤歡迎指正和補充,感謝!

最後,如果你還有什麼問題或者想知道到的,可以在評論區告訴我呦,我可以在後面的文章加上你們的真知灼見。

關注我,看更多幹貨!

我是程序圓,我們下次再見。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章