Linux_C編(2)運算符、表達式

二、運算符、表達式

一、運算符簡介

C語言的運算符可以分爲以下幾類:
(1)算數運算符:用於各類數值運算,包括加(+)、減(-)、乘()、除(/)、取餘或者求模(%)、自增(++)、自減(–),共七種;
(2)關係運算符:用於比較運算,包括大於(>)、小於(<)、等於(==)、大於等於(>=)、小於等於(<=)、不等於(!=),共六種;
(3)邏輯運算符:用於邏輯運算,包括與(&&)、或(||)、非(!),共三種;
(4)位操作運算符:參與運算的量,按照二進制位進行運算,包括位與(&)、位或(|)、位非(~)、位異或(^)、左移(<<)、右移(>>),共六種;注意,並沒有按位同或,按位同或就是異或的取反,同時需要注意按位或和按位與以及按位以爲的區別,具體可以看看位運算的詳解以及
異或的使用

(5)賦值運算符:用於賦值運算,分爲簡單賦值(=)、複合算術賦值(+=、-=、
=、=、%=)、複合位運算賦值(&=、|=、^=、>>=、<<=)三類共十一種;
(6)條件運算符:這是一個三目運算符,用於條件求值(?:);
(7)逗號運算符:用於把若干表達式組合成一個表達式(,);
(8)指針運算符:用於取內容(*)和取地址(&)兩種運算;
(9)求字節數運算符:用於計算數據類型所佔的字節數(sizeof);
(10)特殊運算符:有括號()、下標[]、成員(->、)等幾種。

1. 運算符優先級:
在這裏插入圖片描述在這裏插入圖片描述

在這裏插入圖片描述
上表不容易記住,其實多用用就記得容易了,自己寫代碼的時候可以加入括號,但是閱讀別人的代碼的時候,別人不一定添加括號,不能以自己的標準去衡量別人,這是很重要的。

2、一些容易出錯的優先級問題
優先級問題
(1).的優先級高於*,->操作符用於消除這個問題
例如:*p.f
誤以爲的結果:p所指對象的字段f (*p).f
實際結果:對p取f字段,作爲指針,然後進行接觸引用操作, *(p.f)

(2)[]高於*
例如:int *ap[]
誤以爲的結果:ap是個指向int 數組的指針 int (*ap)[]
實際的結果:ap是個元素爲int 指針的數組 int *(ap[])

(3)函數()高於*
例如:int *fp()
誤以爲的結果:fp是個函數指針,所指函數返回int int(*fp)()
實際結果:fp是個函數,返回int * int *(fp())

(4)==和!=高於位操作
例如:(val & mask!=0)
誤以爲的結果:(val&mask)!=0
實際結果:val & (mask!=0)

(5)==和!=高於賦值符
例如:c = getchar()!=EOF
誤以爲的結果:(c=getchar())!=EOF
實際結果:c = (getchar()!=EOF)

(6)算術運算符高於移位運算符
例如:msb<<4+lsb
誤以爲的結果:(msb<<4)+lsb
實際結果:msb<<(4+lsb)

(7)逗號運算符的優先級在所有的裏面優先級最低
例如:I = 1,2
誤以爲的結果:(I = 1,2)
實際結果:(I = 1),2

3、邏輯運算符
||和&&是我們經常用到的邏輯運算符,與按位與&和按位|或是兩碼事。
例如:

int i = 0;
int j = 0;
if(++i>0)||(++j>0)
{
	//打印出i和j的值
}

結果大家都知道,i=1;j=0
這樣的現象就是所謂的“與斷路”和“或斷路”
即邏輯運算符||兩邊的條件只要有一個爲真,其結果就爲真,只要有一個爲假,那結果就爲假。
詳細的可以看這篇博客C語言中的短路和斷路

二、條件運算符和條件表達式

如果在條件語句中,只執行單個的賦值語句時,常可使用條件表達式來實現,不但使程序簡潔,也可提高運行效率。
條件運算符爲?: 它是一個三目運算符,即有三個參與運算的量,由條件運算符組成條件表達式的一般形式爲
表達式1?表達式2:表達式3
其求值的規則爲:如果表達式1的值爲真,則以表達式2的值作爲條件表達式的值,否則以表達式3的值作爲整個條件表達式的值。
常用來簡化程序,例如:

if (a>b)
{
	max = a;
}
else
{		
	max = b;
}

可以用條件表達式寫成:

max = a>b?a:b;

執行該語句的語義是:如果a>b,就把a賦值給max,否則,把b賦值給max,即求兩個數字的最大值。
使用條件運算符應該注意
(1)條件運算符的運算優先級低於關係運算符和算術運算度,但是高於賦值符。因此:

max = (a>b)?a:b

去掉括號可以寫爲

max = a>b?a:b

(2)條件運算符“?”和“:”是一堆運算符,不能單獨分開使用,也就是不能缺少一個。
(3)條件運算符的結合方向是自右向左結合。例如:

a>b?a:c>d?c:d

應該理解爲

a>b?a:(c>d?c:d)

也就是條件表達式嵌套的用法,一般先從右邊的三目運算開始逐個向左邊開始運算。

三、++、–操作符

++、-- 通常情況下都是令人頭疼的操作符……………………………………
我開始時候也被搞的雲裏霧裏,不知道怎麼算,不過熟練了之後,也就能算對了。
例如:

int i = 3;
(++i)+(++i)+(++i);
//求表達式的值

表達式的值爲多少?樑老師在書上說C語言標準並沒有規定這個,有的編譯器運算出來是18,因爲i經過三次自增後變爲6,然後3個6相加得18,而有的編譯器計算出來得16(我用gcc編譯器,確實得出來16),先計算前兩個i的和,這時候i自加兩次,2個i的和爲10,然後再加上第三次自加的i得16,其實沒有爭議的必要,因爲自己有自己的編譯器,適合自己使用就行。但是無論哪個編譯器都不會算出來是15!
在這裏插入圖片描述
上下兩個結果分別是15,16
區別在於上面的分別用j,k,y來裝了++i,運行結果就是4+5+6,因爲這三個中間變量沒有被賦其他的值。
而下面直接是++i,這三個的變量名其實是一樣的,而自增的運算優先級較高,並且是右結合,從右往左開始計算,最右邊++i之後,i=4,接着算中間的++i,變成5,這時候++i等於5,最右邊的++i也是5,這樣就變成兩個++i相加,等於10,這時候i還是5,再到最左邊的一個++i,i等於6,++i也是6,即6+10=16。
這時候小夥伴可能問我爲什麼自增的優先級高於算術優先級,那爲什麼編譯器不直接先算3個++i,確實,你說的沒錯,有的編譯器確實是這樣,結果等於18,但是也有編譯器等於16,每個編譯器做的時候有自己的想法,就比如vs,他覺得scanf有問題,所以這個函數它會報錯,但是老譚覺得超好用,就直接把stdio的庫加在了第一行,我們究竟這個沒有意義,總之等於18或者16的原因都有了,至於怎麼用,就看你自己的編譯器了。

++、-- 作爲前綴,我們知道是自增或者自減,再做別的運算,但是作爲後綴時,還需要注意什麼時候自增自減。
在這裏插入圖片描述
i = 3;
i++ = 3; i = 4;
i++ = 4; i = 5;
i++ = 5; i = 6;
逗號運算符從左到右依次計算,然後賦值給j,所以j=5,i=6;

逗號運算符的問題

#include<stdio.h>
int main()
{
	int i = 0;
	for(i = 0,printf("Frist = %d",i);i<10,printf("Second = %d",i);i++,printf("Third = %d",i))
	{
		printf("Fourth = %d",i);
	}
}

運行的結果是什麼?爲什麼?
變成

四、位運算

在計算機程序中,數據的位是可以操作的最小數據單位,理論上可以用“位運算”來完成所有的運算和操作,一般的位運算是用來控制硬件的,或者進行數據變換的時候使用。C語言提供了位運算的功能,這使得C語言也能像彙編一樣用來編寫系統程序。
位運算符C語言提供了六種運算符:按位與(&)、按位或(|)、按位異或(^)、取反(~)、左移(<<)、右移(>>)
(1)、按位與運算及應用
按位與運算符(&)是雙目運算符。其功能是參與運算的兩個數字對應的二進制位相與。只有對應的兩個二進制均爲1時,結果位才爲1,否則爲0。參與運算的數以補碼方式出現,例如:
9&5:
0000 1001 (9的二進制補碼)& 0000 0101(5的二進制補碼)
0000 0001(1的二進制補碼)
所以9&5=1
按位與運算通常用來對某些位清零或者保留某些位。例如:把a的高八位清零,保留低八位,可以用a&255運算,因爲255的二進制補碼爲0000000011111111
(2)、按位或運算及應用
按位或運算符“|”是一個雙目運算符,其功能是參與運算的兩個數字對應的二進制位相或。只要對應的兩個二進制位有一個是1時,結果位就是1,參與運算 兩個數字以補碼方式出現。
同樣,我們用9|5來舉例:
0000 1001 | 0000 0101
0000 1101 (十進制爲13)
可見9|5=13
應用:常用來將源操作數某些位置一,其他位保持不變。
(3)、按位異或運算及應用
按位異或運算符“^”是一個雙目運算符,其功能是參與運算的兩個數字對應的二進制位相異或,當兩對應的二進制相異時,結果爲1。參與運算數還是以補碼方式出現。
例如:
9^5:
0000 1001 ^ 0000 0101
0000 1100(12)
應用:
使特定位的值取反
不引入第三變量,交換兩個變量的值。
異或的特徵:
x^x = 0;
x^0 = x;
a = a^b;
b = a^b; //因爲這裏b = a ^ b ^ b,異或有結合律,根據特徵,後面爲0,a^0=a;b = a;
a = a^b;
(4)左移和右移
左移(<<)是雙目運算符,其功能是把"<<“左邊的運算數的各個二進制位全部左移若干位,由”<<"右邊的數指定移動的位數,高位丟棄,低位補零;
右移(>>)是雙目運算符,其功能和左移相反,但是注意:對於有符號位的數,在右移時,符號位也跟隨移動,當爲正數時,最高位補0,當爲負數時,最高位補1。

(五)、C語言性能優化:使用位操作

使用位操作可以減少除法和取模的運算,在計算機程中數據的位是可以操作的小數據單位,理論上可以用“位運算”來完成所有的運算和操作。一般的位操作時用來控制硬件的,或者進行數據交換,但是,靈活的位操作可以有效地提高程序運行的效率。

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