亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

再識(shí)C語言(五)

BigTomato / 1215人閱讀

摘要:注不要移動(dòng)負(fù)數(shù)位標(biāo)準(zhǔn)未定義行為這種行為屬于標(biāo)準(zhǔn)未定義行為語言中并沒有規(guī)定移動(dòng)負(fù)數(shù)位。按進(jìn)制位與規(guī)則兩個(gè)二進(jìn)制數(shù),有則為,全則為。為假的時(shí)候,打印語言中表示假,非表示真無論是正數(shù)還是負(fù)數(shù)。

C語言操作符詳解

目錄

一、算術(shù)操作符

二、移位操作符

三、位操作符

四、賦值操作符

五、單目操作符

六、關(guān)系操作符

七、邏輯操作符

八、條件操作符

九、逗號(hào)表達(dá)式

十、下標(biāo)引用、函數(shù)調(diào)用和結(jié)構(gòu)體成員操作符

?十一、表達(dá)式求值

十二、 操作符查閱表

總結(jié)


C語言中的操作符有:

算術(shù)操作符、移位操作符、位操作符、賦值操作符、單目操作符、關(guān)系操作符、邏輯操作符、

條件操作符、逗號(hào)表達(dá)式、下標(biāo)引用操作符、函數(shù)調(diào)用操作符、結(jié)構(gòu)成員訪問操作符

一、算術(shù)操作符

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

?+(加)-(減)*(乘)與數(shù)學(xué)中的類似,這里就不過多的敘述了。

(1)% : 取模(取余)得到的是相除之后的余數(shù)

?(2)/ :除法 得到的是商

  • 當(dāng)? /(除號(hào))兩端都是整數(shù)時(shí),執(zhí)行的是整數(shù)除法,整數(shù)除法得到的結(jié)果是整數(shù)部分,小數(shù)部分直接舍去。
  • 兩端只要有一個(gè)浮點(diǎn)數(shù),執(zhí)行的就是浮點(diǎn)數(shù)的除法,浮點(diǎn)數(shù)除法默認(rèn)保留6位小數(shù)。

總結(jié):

  1. 除了 % 操作符之外,其他的幾個(gè)操作符可以作用于整數(shù)和浮點(diǎn)數(shù)。
  2. ?對于 /(除) 操作符如果兩個(gè)操作數(shù)都為整數(shù),執(zhí)行整數(shù)除法。而只要有浮點(diǎn)數(shù)執(zhí)行的就是浮點(diǎn)數(shù)除法。
  3. % 操作符的兩個(gè)操作數(shù)必須為整數(shù)。返回的是整除之后的余數(shù)。

二、移位操作符

<<:左移操作符

>>:右移操作符

注:移位操作符的操作數(shù)只能是整數(shù)

移位操作符移動(dòng)的是整數(shù)的二進(jìn)制位

先了解一下C語言中的二進(jìn)制位

二進(jìn)制與十進(jìn)制的轉(zhuǎn)換

例:二進(jìn)制數(shù):1 1 1 1 ---------> 1*2^3+1*2^2+1*2^1+1*2^0 = 15 (十進(jìn)制)

??????? 二進(jìn)制不好理解,可以想一想十進(jìn)制的:? 1 2 3 ---------> 1*10^2+2*10^1+3*10^0 = 123

??????? 十進(jìn)制:5? 轉(zhuǎn)換為二進(jìn)制: 0101 ---------> 0*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 5

二進(jìn)制、八進(jìn)制、十進(jìn)制、十六進(jìn)制只是數(shù)值的表示形式

整數(shù)有三種二進(jìn)制的表示形式:原碼、反碼、補(bǔ)碼

正整數(shù):原碼、反碼、補(bǔ)碼相同

負(fù)整數(shù):原碼、反碼、補(bǔ)碼不同,要進(jìn)行計(jì)算!

正整數(shù):int a = 5;a是整型,a占4個(gè)字節(jié) -->32bit

直接將十進(jìn)制數(shù)轉(zhuǎn)換成為對應(yīng)的二進(jìn)制數(shù)得到的是原碼

a的原碼:00000000000000000000000000000101

a的反碼:00000000000000000000000000000101

a的補(bǔ)碼:00000000000000000000000000000101

最高位0表示正數(shù)

負(fù)整數(shù):int b = -5;b是整型,b占4個(gè)字節(jié) -->32bit

負(fù)數(shù)原碼、反碼、補(bǔ)碼的計(jì)算:

原碼:直接將十進(jìn)制數(shù)轉(zhuǎn)換成為對應(yīng)的二進(jìn)制數(shù)

反碼:原碼的符號(hào)位(最高位)不變,其他位按位取反

補(bǔ)碼:反碼+1

b的原碼:1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0? 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1

b的反碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0

b的補(bǔ)碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1

最高位1表示負(fù)數(shù)

整數(shù)在內(nèi)存中存儲(chǔ)的是補(bǔ)碼

可以看一下內(nèi)存中存儲(chǔ)是是不是補(bǔ)碼

使用-1來驗(yàn)證

-1的原碼:1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0? 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

-1的反碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0

-1的補(bǔ)碼:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

?十六進(jìn)制數(shù)使用 0 1 2 3 4 5 6 7 8 9 a b c d e f 表示

二進(jìn)制 1 1 1 1 是十進(jìn)制的15;十六進(jìn)制的 f 是十進(jìn)制的15

ff ff ff ff 寫成二進(jìn)制形式:

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

由此可以知道整數(shù)在內(nèi)存中存儲(chǔ)的是補(bǔ)碼。

1、左移操作符: <<

移位規(guī)則: 左邊拋棄、右邊補(bǔ)0

正數(shù):

#includeint main(){	int a = 5;	//將a在內(nèi)存中存儲(chǔ)的二進(jìn)制位向左移動(dòng)兩位	int b = a << 2;	printf("%d/n", b);    printf("%d/n", a);	return 0;}

代碼分析

雖然變量a左移兩位后值發(fā)生了變化,但a的值不會(huì)發(fā)生變化,就相當(dāng)于 b = a+1,b的值發(fā)生了變化,a的值不會(huì)變。

運(yùn)行結(jié)果

?負(fù)數(shù):

#includeint main(){	int b = -5;	//將b在內(nèi)存中存儲(chǔ)的二進(jìn)制位向左移動(dòng)兩位	int c = b << 2;	printf("%d/n", c);	printf("%d/n", b);	return 0;}

代碼分析

?運(yùn)行結(jié)果

?2、右移操作符: >>

(1)算術(shù)右移

規(guī)則:右邊丟棄,左邊補(bǔ)原來的符號(hào)位

(2)邏輯右移

規(guī)則:右邊丟棄,左邊補(bǔ)0(如果是負(fù)數(shù),左邊補(bǔ)0得到的是正數(shù))

算術(shù)右移與邏輯右移取決于編譯器,C語言中并沒有規(guī)定具體使用哪種右移。我們常見的編譯器下都是算術(shù)右移。

正數(shù):

#includeint main(){	int a = 5;	//將a在內(nèi)存中存儲(chǔ)的二進(jìn)制位向右移動(dòng)1位	int b = a >> 1;	printf("%d/n", b);	printf("%d/n", a);	return 0;}

代碼分析

運(yùn)行結(jié)果

負(fù)數(shù):

#includeint main(){	int a = -5;	//將a在內(nèi)存中存儲(chǔ)的二進(jìn)制位向右移動(dòng)1位	int b = a >> 1;	printf("%d/n", b);	printf("%d/n", a);	return 0;}

代碼分析

運(yùn)行結(jié)果

?由代碼的運(yùn)行結(jié)果得到,當(dāng)前編譯器采用的是算術(shù)右移(左邊補(bǔ)符號(hào)位)。

注:不要移動(dòng)負(fù)數(shù)位

int a = 10;int b = a >> -2; //標(biāo)準(zhǔn)未定義行為

這種行為屬于標(biāo)準(zhǔn)未定義行為(C語言中并沒有規(guī)定移動(dòng)負(fù)數(shù)位)。

三、位操作符

&:按位與??????? |:按位或??????? ^:按位異或

注:他們的操作數(shù)必須是整數(shù),操作的是整數(shù)的補(bǔ)碼。

1、按(2進(jìn)制)位與:&

規(guī)則:兩個(gè)二進(jìn)制數(shù),有0則為0,全1則為1。

#includeint main(){	int a = -3;	int b = -5;	int c = a & b;	printf("%d/n", c);	return 0;}

計(jì)算過程

?運(yùn)行結(jié)果

2、按(2進(jìn)制)位或:|

規(guī)則:兩個(gè)二進(jìn)制數(shù),有1則為1,全0則為0。

#includeint main(){	int a = 3;	int b = -5;	int c = a | b;	printf("%d/n", c);	return 0;}

計(jì)算過程

?運(yùn)行結(jié)果

3、按(2進(jìn)制)位異或:^

規(guī)則:兩個(gè)二進(jìn)制數(shù),相同為0,相異為1。

#includeint main(){	int a = 3;	int b = -5;	int c = a ^ b;	printf("%d/n", c);	return 0;}

計(jì)算過程

?運(yùn)行結(jié)果

4、位操作符練習(xí)

不創(chuàng)建臨時(shí)變量(第三個(gè)變量),實(shí)現(xiàn)兩個(gè)數(shù)的交換。

方法一:

#includeint main(){	int a = 3;	int b = 5;	printf("交換前:a=%d b=%d/n", a, b);	a = a + b;	b = a - b;	a = a - b;	printf("交換后:a=%d b=%d/n", a, b);	return 0;}

運(yùn)行結(jié)果

這種方法雖然可以實(shí)現(xiàn)不創(chuàng)建臨時(shí)變量交換兩個(gè)數(shù)的效果,但是當(dāng)兩個(gè)數(shù)加起來的結(jié)果超過了整型的范圍就會(huì)出錯(cuò),這種方法不能滿足任意兩個(gè)整數(shù)的交換。

方法二:

#includeint main(){	int a = 3;	int b = 5;	printf("交換前:a=%d b=%d/n", a, b);	a = a ^ b;	b = a ^ b;//b = a ^ b ^ b 	a = a ^ b;//a = a ^ a ^ b	printf("交換后:a=%d b=%d/n", a, b);	return 0;}

?運(yùn)行結(jié)果

?這種方法可讀性太差,實(shí)際中交換兩個(gè)變量應(yīng)用最多的方法是創(chuàng)建臨時(shí)變量來進(jìn)行交換。這里只是練習(xí)使用位操作符。

四、賦值操作符

1、= :賦值操作符

賦值操作符是一個(gè)很棒的操作符,他可以讓你得到一個(gè)你之前不滿意的值。也就是你可以給自己重新賦值。

	int a = 10;	a = 100; //賦值操作符

賦值操作符可以連續(xù)賦值,但是不建議這樣寫。

#includeint main(){	int a = 10;	int b = 0;	int c = 20;	a = b = c + 1;//連續(xù)賦值	printf("%d/n", a);	return 0;}

運(yùn)行結(jié)果

上面的寫法等同于

    int a = 10;	int b = 0;	int c = 20;	b = c + 1;	a = b;

補(bǔ)充:

賦值操作符必須保證左邊是變量

  • ?左值,是可以放在等號(hào)左邊的,一般是一塊空間(變量)。
  • 右值,是可以放在等號(hào)右邊的,一般是一個(gè)值,或者是一塊空間的內(nèi)容。

2、復(fù)合賦值符

+=:加等???????? -=:減等???????? *= :乘等??????? /=:除等???????? %=:取模等

>>=:右移等??????? <<=:左移等???????? &=:按位與等???????? |=:按位或等???????? ^=:按位異或等

#includeint main(){	int a = 10;	int b = -5;	int c = 0;	a += 10;//等同于:a = a + 10;	c ^= b;//等同于:c = c ^ b;	printf("%d/n", a);	printf("%d/n", c);	return 0;}

其他運(yùn)算符一樣的道理。這樣寫更加簡潔。?

五、單目操作符

3 + 5:

  • 3 是左操作數(shù)
  • + 是一個(gè)操作符
  • 5 是右操作數(shù)

+ 有兩個(gè)操作數(shù),它是雙目操作符

單目操作符只有一個(gè)操作數(shù)

!:邏輯反操作??????? -:負(fù)值??????? +:正值??????? &:取地址???????

sizeof:計(jì)算操作數(shù)的類型長度(以字節(jié)為單位)

~:對一個(gè)數(shù)的二進(jìn)制按位取反????? ? --:前置、后置--(減1)?????? ++:前置、后置++(加1)

*:間接訪問操作符(解引用操作符)??????? (類型):強(qiáng)制類型轉(zhuǎn)換

1、!:邏輯反操作

將一個(gè)表達(dá)式的結(jié)果,真變?yōu)榧?,假變?yōu)檎妗?/span>

#includeint main(){	int flag = 0;	//flag 為假的時(shí)候,打印hehe	if (!flag)	{		printf("hehe/n");	}	return 0;}

C語言中0表示假,非0表示真(無論是正數(shù)還是負(fù)數(shù))。

  • !真:表示假
  • !0:表示真,!0 的值為 1

2、? - :負(fù)值

#includeint main(){	int i = 0;	int a = -10;	int flag = 1;	for (i = 0; i < 10; i++)	{		printf("%d ", i * flag);		flag = -flag;	}	return 0;}

運(yùn)行結(jié)果

?3、+:正值

這個(gè)符號(hào)沒什么用,對于正數(shù)加上+還是正數(shù),對于負(fù)數(shù)加上+還是負(fù)數(shù)。

4、&取地址

#includeint main(){	int a = 10;	&a;//& - 取地址操作符,獲取變量的地址	return 0;}

5、sizeof:計(jì)算操作數(shù)的類型長度(以字節(jié)為單位)

#includeint main(){	int a = 10;	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };	printf("%d/n", sizeof(a));	printf("%d/n", sizeof(int));	printf("%d/n", sizeof a);//因?yàn)閟izeof是操作符,所以不加括號(hào)也行    //下面這種寫法不可以,sizeof在計(jì)算變量大小時(shí)才可以省略括號(hào),    //sizeof在計(jì)算類型大小時(shí)不可以將括號(hào)省略。建議在寫的時(shí)候都加上括號(hào)。	printf("%d/n", sizeof int);//error	//計(jì)算數(shù)組的大?。?printf("%d/n", sizeof(arr));	printf("%d/n", sizeof(int [10]));//int [10] ->是數(shù)組 arr 的類型	return 0;}

?運(yùn)行結(jié)果

#includevoid test1(int arr[]){	printf("%d/n", sizeof(arr));}void test2(char ch[]){	printf("%d/n", sizeof(ch));}int main(){	int arr[10] = { 0 };	char ch[10] = { 0 };	printf("%d/n", sizeof(arr));	printf("%d/n", sizeof(ch));	test1(arr);	test2(ch);	return 0;}

代碼分析

運(yùn)行結(jié)果

6、~ 按(內(nèi)存中補(bǔ)碼的二進(jìn)制)位取反

#includeint main(){	int a = 0;	int b = ~a;	printf("%d/n", b);	return 0;}

計(jì)算過程

0的補(bǔ)碼:00000000000000000000000000000000

按位取反(~0)后:

補(bǔ)碼:11111111111111111111111111111111
反碼:11111111111111111111111111111110
原碼:10000000000000000000000000000001

結(jié)果: - 1

~ 按位取反的使用:

#includeint main(){	int a = 10;	a |= (1 << 2);	printf("%d/n", a);	a &= ~(1 << 2);	printf("%d/n", a);	return 0;}

?運(yùn)行結(jié)果

?7、++:前置、后置++(加1)

前置++:先++,后使用

#includeint main(){	int a = 10;	int b = ++a;	printf("a=%d b=%d/n", a, b);	return 0;}

運(yùn)行結(jié)果

?后置++:先使用,再++

#includeint main(){	int a = 10;	int b = a++;//先將a的值賦給b,再++	printf("a=%d b=%d/n", a, b);	return 0;}

運(yùn)行結(jié)果

#includeint main(){	int a = 10;	printf("%d/n", a++); //值為10	return 0;}
#includeint main(){	int a = 10;	printf("%d/n", ++a); //值為11	return 0;}

?8、 --:前置、后置--(減1)

前置--:先--,后使用

#includeint main(){	int a = 10;	int b = --a;//先將a的值賦給b,再++	printf("a=%d b=%d/n", a, b);	return 0;}

運(yùn)行結(jié)果

??后置--:先使用,再--

#includeint main(){	int a = 10;	int b = a--;//先將a的值賦給b,再++	printf("a=%d b=%d/n", a, b);	return 0;}

運(yùn)行結(jié)果

自增自減(++、--)不要整的太復(fù)雜

#includeint main(){	int a = 1;	int b = (++a) + (++a) + (++a);	printf("%d/n", b);	printf("%d/n", a);	return 0;}

?運(yùn)行結(jié)果

同樣的代碼在Linux環(huán)境下使用 gcc 編譯器運(yùn)行的結(jié)果

?由結(jié)果可以看出,這個(gè)代碼是一種錯(cuò)誤的代碼,在不同的編譯器下運(yùn)行會(huì)得到不同的結(jié)果。

?9、 *:間接訪問操作符(解引用操作符)

#includeint main(){	int a = 10;	int* pa = &a;	*pa = 20;//* ->解引用操作符(間接訪問操作符)	printf("%d/n", a);	return 0;}

?代碼分析

?運(yùn)行結(jié)果

?10、(類型)強(qiáng)制類型轉(zhuǎn)換

#includeint main(){	int a =(int)3.14;//3.14 ->double類型	printf("%d/n", a);	return 0;}

?將double類型的數(shù)據(jù)強(qiáng)制類型轉(zhuǎn)換為整型后,得到是結(jié)果是整數(shù)部分,小數(shù)部分直接舍去。

運(yùn)行結(jié)果

強(qiáng)制類型轉(zhuǎn)換不建議大量的使用,創(chuàng)建變量時(shí)盡量將類型匹配。

六、關(guān)系操作符

>:大于??????? >=:大于等于 ?????? <:小于??????? <=:小于等于??????? !=:不等于??????? ==:等于

關(guān)系操作符比較簡單,直接使用就可以了。

要注意:在編程的過程中容易將==和=不小心寫錯(cuò)。==是用于測試兩個(gè)值相等,=是賦值。

七、邏輯操作符

&&:邏輯與??????? ||:邏輯或

區(qū)分邏輯操作符和按位操作符:

  • 按位與 & 和按位或 | :這兩個(gè)操作符是操作二進(jìn)制位的。
  • 邏輯操作符:只關(guān)注變量值的真和假。

1、 &&:邏輯與

  • &&操作符左邊為假(0),就不會(huì)計(jì)算操作符右邊的表達(dá)式,整個(gè)表達(dá)式的結(jié)果為假。
  • 操作符左邊為真,會(huì)繼續(xù)計(jì)算操作符右邊的表達(dá)式。
  • 操作符兩邊只要有一個(gè)表達(dá)式的值為假,整個(gè)表達(dá)式的結(jié)果為假,值為0。
  • 只有兩個(gè)同時(shí)為真,整個(gè)表達(dá)式的結(jié)果才為真,值為1。

練習(xí)

#include int main(){    int i = 0, a = 0, b = 2, c = 3, d = 4;    i = a++ && ++b && d++;    printf("a = %d/nb = %d/nc = %d/nd = %d/n", a, b, c, d);    return 0;}

代碼分析

a=0,a++先返回a=0,a再自增(a的值為1)。當(dāng)a返回的值為0時(shí)就不會(huì)再計(jì)算&&后面的表達(dá)式,所以,a的值為1,b的值為2,c的值為3,d的值為4。最會(huì)輸出結(jié)果,a = 1,b = 2 ,c = 3,d = 4。

運(yùn)行結(jié)果

2、||:邏輯或

  • ||邏輯或操作符左邊為真,就不會(huì)計(jì)算操作符左邊的表達(dá)式,整個(gè)表達(dá)式的結(jié)果為真。
  • 操作符左邊為假,會(huì)繼續(xù)計(jì)算操作符右邊的表達(dá)式。
  • 操作符兩邊只要有一個(gè)表達(dá)式的值為真,整個(gè)表達(dá)式的結(jié)果為真,值為1。
  • 只有兩個(gè)都為假,整個(gè)表達(dá)式的結(jié)果為假,值為0。
#include int main(){    int i = 0, a = 0, b = 2, c = 3, d = 4;    i = a++||++b||d++;    printf("a = %d/nb = %d/nc = %d/nd = %d/n", a, b, c, d);    return 0;}

?代碼分析

a=0,a++先返回a=0,a再自增(a的值為1)。當(dāng)a返回的值為0時(shí)計(jì)算 || 后面的表達(dá)式,b=2,++b先執(zhí)行b自增1,再返回自增后的結(jié)果為3。當(dāng)b=3時(shí),表達(dá)式(++b)的結(jié)果為真,不會(huì)再計(jì)算||后的表達(dá)式。所以a的值為1,b的值為3,c的值為3,d的值為4。最會(huì)輸出結(jié)果,a = 1,b = 3 ,c = 3,d = 4。

運(yùn)行結(jié)果

?總結(jié)

&&:左操作數(shù)為假,右邊不計(jì)算

||:左操作數(shù)作為真,右邊不計(jì)算

八、條件操作符

表達(dá)式1 ?? 表達(dá)式2 : 表達(dá)式3

如果表達(dá)式1的結(jié)果為真,則執(zhí)行表達(dá)式2,整個(gè)表達(dá)式的結(jié)果為表達(dá)式2執(zhí)行的結(jié)果

如果表達(dá)式1的結(jié)果為假,則執(zhí)行表達(dá)式3,整個(gè)表達(dá)式的結(jié)果為表達(dá)式3執(zhí)行的結(jié)果

#includeint main(){	int a = 10;	int b = 20;	int max = 0;	max = (a > b ? a : b);	printf("%d/n", max);	return 0;}

九、逗號(hào)表達(dá)式

表達(dá)式1,表達(dá)式2,表達(dá)式3 …… 表達(dá)式n

逗號(hào)表達(dá)式,就是由逗號(hào)隔開的多個(gè)表達(dá)式。

逗號(hào)表達(dá)式,從左向右依次執(zhí)行。整個(gè)表達(dá)式的結(jié)果是最后一個(gè)表達(dá)式的結(jié)果。

#includeint main(){	int a = 3;	int b = 5;	int c = 6;	int d = (a += 2, b = a - c, c = a + 2 * b);	printf("%d/n", d);	return 0;}

代碼分析

  • 先計(jì)算,a += 2,a = 3 + 2 = 5
  • 再計(jì)算b = a - c,b = 5 - 6 = -1
  • 再計(jì)算c = a + 2 * b,c = 5 + 2 * (-1) = 3
  • d的結(jié)果為最后一個(gè)表達(dá)式的結(jié)果,所以輸出d的值為3。

運(yùn)行結(jié)果

?逗號(hào)表達(dá)式的使用

#includeint main(){	int a = 5;	int count = 0;	while (count < 10)	{		a = a+1;		count++;	}	//簡潔的寫法	while (a = a + 1, count++, count < 10)	{		;	}	return 0;}

十、下標(biāo)引用、函數(shù)調(diào)用和結(jié)構(gòu)體成員操作符

1、 [ ],下標(biāo)引用操作符

操作數(shù):數(shù)組名+元素下標(biāo)

#includeint main(){	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };	printf("%d/n", arr[7]);//[]就是下標(biāo)引用操作符,arr 和 7是操作數(shù)	return 0;}

運(yùn)行結(jié)果

補(bǔ)充:

其實(shí)編譯器在編譯arr[7]時(shí),是將arr[7]轉(zhuǎn)換成 *(arr+7)再對數(shù)組訪問。

*(arr+7) :arr是數(shù)組首元素的地址,arr+7就表示從數(shù)組首元素來說找到第8個(gè)元素(數(shù)組下標(biāo)是從0開始的,所以找到的是第8個(gè)元素)。

arr[7] ---> *(arr+7) --->*(7+arr) --->7[arr]

這里只是推導(dǎo)一下有這種形式,但在寫代碼的時(shí)候還是正常寫比較好。

2、 ( ) 函數(shù)調(diào)用操作符

接受一個(gè)或者多個(gè)操作數(shù):第一個(gè)操作數(shù)是函數(shù)名,剩余的操作數(shù)就是傳遞給函數(shù)的參數(shù)。

無參函數(shù),函數(shù)名就是操作數(shù),有參函數(shù),函數(shù)名和參數(shù)都是操作數(shù)。

3、訪問一個(gè)結(jié)構(gòu)的成員

  • . ? 結(jié)構(gòu)體.成員名
  • -> 結(jié)構(gòu)體指針->成員名
#includestruct Stu{	char name[20];	int age;	double score;};int main(){	struct Stu s = { "zhangsan",20,85.5 };	// . 操作符	//結(jié)構(gòu)體變量.結(jié)構(gòu)體成員	printf("%s %d %.1f/n", s.name, s.age, s.score);	// -> 操作符	struct Stu* ps = &s;	printf("%s %d %.1f/n", (*ps).name, (*ps).age, (* ps).score);	//結(jié)構(gòu)體指針->結(jié)構(gòu)體成員	printf("%s %d %.1f/n", ps->name, ps->age, ps->score);	return 0;}

運(yùn)行結(jié)果

?十一、表達(dá)式求值

表達(dá)式求值的順序一部分是由操作符的優(yōu)先級和結(jié)合性決定。

有些表達(dá)式的操作數(shù)在求值的過程中可能需要轉(zhuǎn)換為其他類型。

1、隱式類型轉(zhuǎn)換

C的整型算術(shù)運(yùn)算總是至少以缺省整型類型的精度來進(jìn)行的。

為了獲得這個(gè)精度,表達(dá)式中的字符和短整型操作數(shù)在使用之前被轉(zhuǎn)換為普通整型,這種轉(zhuǎn)換稱為整型提升。

(1)整型提升的意義

表達(dá)式的整型運(yùn)算要在CPU的相應(yīng)運(yùn)算器件內(nèi)執(zhí)行,CPU內(nèi)整型運(yùn)算器(ALU)的操作數(shù)的字節(jié)長度 一般就是int的字節(jié)長度,同時(shí)也是CPU的通用寄存器的長度。

因此,即使兩個(gè)char類型的相加,在CPU執(zhí)行時(shí)實(shí)際上也要先轉(zhuǎn)換為CPU內(nèi)整型操作數(shù)的標(biāo)準(zhǔn)長 度再計(jì)算。

通用CPU(general-purpose CPU)是難以直接實(shí)現(xiàn)兩個(gè)8比特字節(jié)直接相加運(yùn)算(雖然機(jī)器指令 中可能有這種字節(jié)相加指令)。所以,表達(dá)式中各種長度可能小于int長度的整型值,都必須先轉(zhuǎn) 換為int或unsigned int,然后才能送入CPU去執(zhí)行運(yùn)算。

(2)整型提升的計(jì)算過程

整型提升是按照變量的數(shù)據(jù)類型的符號(hào)位來提升的。

#includeint main(){	char a = 5;	char b = 126;	char c = a + b;	printf("%d/n", c);	return 0;}

執(zhí)行過程

?運(yùn)行結(jié)果

參與運(yùn)算的數(shù)據(jù)類型是char和char計(jì)算,char和short計(jì)算,short和short計(jì)算都會(huì)發(fā)生整型提升。

整型提升的例子

(1)

#includeint main(){	char a = 0xb6;	short b = 0xb600;	int c = 0xb6000000;	if (a == 0xb6)		printf("a/n");	if (b == 0xb600)		printf("b/n");	if (c == 0xb6000000)		printf("c/n");	return 0;}

代碼分析

  • 變量 a 和 b要進(jìn)行整形提升,但是變量c是整型所以不需要整形提升。
  • a和b整形提升之后就變成了負(fù)數(shù),所以表達(dá)式 a==0xb6 , b==0xb600 的結(jié)果為假。
  • c不發(fā)生整形提升,所以表達(dá)式 c==0xb6000000 的結(jié)果是真. 所程序輸出的結(jié)果是: c

運(yùn)行結(jié)果

(2)

#includeint main(){	char c = 1;	printf("%u/n", sizeof(c));	printf("%u/n", sizeof(+c));	printf("%u/n", sizeof(-c));	return 0;}

代碼分析

  • 變量c只要參與表達(dá)式運(yùn)算,就會(huì)發(fā)生整形提升。
  • 表達(dá)式 +c 就會(huì)發(fā)生提升,所以 sizeof(+c) 是4個(gè)字節(jié)。表達(dá)式 -c 也會(huì)發(fā)生整形提升,所以 sizeof(-c) 是4個(gè)字節(jié),但是 sizeof(c) ,就是1個(gè)字節(jié)。
  • 最后輸出的結(jié)果是:1 4 4

運(yùn)行結(jié)果

補(bǔ)充:sizeof(),括號(hào)內(nèi)的表達(dá)式不參與運(yùn)算。

??? int a = 10;
?? ?int b = 20;
?? ?a + b;?????

  • 表達(dá)式有兩個(gè)屬性:值屬性,類型屬性
  • a+b 中:30就是值屬性,int就是類型屬性
  • 當(dāng)知道類型屬性時(shí),sizeof是通過類型屬性判斷表達(dá)式有幾個(gè)字節(jié),所以不需要計(jì)算。表達(dá)式的值。
#includeint main(){	short s = 20;	int a = 5;	printf("%d/n", sizeof(s = a + 4));	printf("%d/n", s);	return 0;}

?代碼分析

  • a是整型,a+4表達(dá)式的類型是int,將a+4放到變量s中,但是s是short類型,所以表達(dá)式的類型就變成了short類型。所以sizeof計(jì)算的是short類型字節(jié)的大小,結(jié)果是2。
  • sizeof()括號(hào)中的表達(dá)式不會(huì)真實(shí)計(jì)算,所以s的值還是20。
  • 最后輸出的結(jié)果是 2? 20

運(yùn)行結(jié)果

2、算術(shù)轉(zhuǎn)換

?如果某個(gè)操作符的各個(gè)操作數(shù)屬于不同的類型,那么除非其中一個(gè)操作數(shù)的轉(zhuǎn)換為另一個(gè)操作數(shù)的類 型,否則操作就無法進(jìn)行。下面的層次體系稱為尋常算術(shù)轉(zhuǎn)換。

  1. long double???????
  2. double???????
  3. float???????
  4. unsigned long int???????
  5. long int???????
  6. unsigned int???????
  7. int
  • 上面這些類型之間轉(zhuǎn)換是由下往上轉(zhuǎn)換。
  • 例:int 類型的數(shù)與flaot類型的數(shù)進(jìn)行計(jì)算,最終計(jì)算的結(jié)果應(yīng)該是float類型。

如果某個(gè)操作數(shù)的類型在上面這些列表中排名較低,那么首先要轉(zhuǎn)換為另外一個(gè)操作數(shù)的類型后執(zhí)行運(yùn)算。
?

#includeint main(){	int a = 5;	float b = 3.14;	float r = a + b;//算術(shù)轉(zhuǎn)換	return 0;}

小于4個(gè)字節(jié)的類型之間計(jì)算是整型提升,其他類型之間計(jì)算時(shí)算術(shù)轉(zhuǎn)換。

注: 算術(shù)轉(zhuǎn)換要合理,要不然會(huì)有一些潛在的問題。

3、操作符的屬性

復(fù)雜表達(dá)式的求值有三個(gè)影響的因素。

  1. 操作符的優(yōu)先級
  2. 操作符的結(jié)合性
  3. 是否控制求值順序。

兩個(gè)相鄰的操作符取決于他們的優(yōu)先級。如果兩者的優(yōu)先級相同,取決于他們的結(jié)合性。

(1)操作符優(yōu)先級

#includeint main(){	int a = 10;	int b = 20;	int c = a + b * c;	return 0;}

乘法的優(yōu)先級高于加法,所以先計(jì)算乘法再計(jì)算加法。

(2)操作符結(jié)合性

相鄰操作符的優(yōu)先級相同的情況下,取決于結(jié)合性。

#includeint main(){	int a = 10;	int b = 20;	int c = a + b + c;	return 0;}

加法的結(jié)合性是從左向右計(jì)算。所以先計(jì)算a+b,再將a+b計(jì)算出的結(jié)果與c進(jìn)行計(jì)算。

一些問題表達(dá)式有了優(yōu)先級和結(jié)合性也不能準(zhǔn)確的確定表達(dá)式的計(jì)算結(jié)果

(1)代碼1

a * b + c * d + e * f

這個(gè)表達(dá)式?jīng)]有唯一確定的計(jì)算順序

第一種:

  1. 計(jì)算a * b
  2. 計(jì)算c * d
  3. 計(jì)算e * f
  4. 計(jì)算a * b? +? c*d
  5. 計(jì)算a * b? +? c * d + e * f

第二種:

  1. 計(jì)算a * b
  2. 計(jì)算c * d
  3. 計(jì)算a * b? +? c*d
  4. 計(jì)算e * f
  5. 計(jì)算a * b? +? c * d + e * f

如果a,b,c,d,e,f 每個(gè)都是一個(gè)表達(dá)式,那么兩種計(jì)算順序得到的結(jié)果肯定不同。

由于*比+的優(yōu)先級高,只能保證,*的計(jì)算是比+早,但是優(yōu)先級并不 能決定第三個(gè)*比第一個(gè)+早執(zhí)行。

(2)代碼2

#includeint main(){	int c = 5;	c + --c;	return 0;}

?這個(gè)代碼中--的優(yōu)先級高于+,但是c的取值不確定。

  1. 加號(hào)的左操作數(shù)先準(zhǔn)備讓c=5,先計(jì)算--c,c = 4。5 + 4=9
  2. 加號(hào)的左操作數(shù)不準(zhǔn)備,先計(jì)算--c,c = 4。4 + 4 = 8

操作符的優(yōu)先級只能決定自減--的運(yùn)算在+的運(yùn)算的前面,但是我們并沒有辦法得知,+操作符的左操作數(shù)的獲取在右操作數(shù)之前還是之后求值,所以結(jié)果是不可預(yù)測的,是有歧義的。

(3)代碼3

#inclu           
               
                                           
                       
                 

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/124773.html

相關(guān)文章

  • JS魔法堂:再識(shí)instanceof

    摘要:一大家都知道一般就是用來檢查對象是否為類或子類的實(shí)例。中兩者均指向,因此添加到的屬性,也會(huì)出現(xiàn)在的中。四其實(shí)是建議實(shí)現(xiàn)者如采用的底層優(yōu)化手段。因?yàn)橹卸x函數(shù)啥都一樣,所以底層實(shí)現(xiàn)可以不再生成一個(gè)新的,從而從空間和時(shí)間上降低消耗。 一、Breif                             大家都知道instanceof一般就是用來檢查A對象是否為B類或子類的實(shí)例。那問題是...

    gself 評論0 收藏0
  • PHP擴(kuò)展開發(fā)系列01 - 我要成為一名老司機(jī)

    摘要:找找出別人擴(kuò)展真么寫的。這次主要說了下寫擴(kuò)展要準(zhǔn)備的一些基本知識(shí)。比如不同編譯方式這個(gè)你看別的擴(kuò)展源碼的時(shí)候就會(huì)注意到具體作用。后面再來慢慢學(xué)習(xí)老司機(jī)的各種姿勢。包括,函數(shù),函數(shù)參數(shù),函數(shù)返回值,對象,類,命名空間等等等。 PHP擴(kuò)展開發(fā)系列01 - 我要成為一名老司機(jī) 1. 關(guān)于擴(kuò)展的教程貌似挺全了,為啥還寫? 記錄下我寫擴(kuò)展的歷程 自認(rèn)為會(huì)寫的更容易理解 我的宗旨就是 先用再識(shí) ...

    30e8336b8229 評論0 收藏0
  • 分鐘殺穿指針 pointer——C語言專題

    摘要:另外,通過指針可以更便捷地操作數(shù)組。在一定意義上可以說,指針是語言的精髓。野指針成因除了未初始化還有就是越界訪問或者指針指向空間已經(jīng)釋放。所以不難知道兩個(gè)地址相減就是元素的個(gè)數(shù),這個(gè)表達(dá)式的前提是兩個(gè)指針指向同一塊空間。 ...

    MycLambert 評論0 收藏0
  • 分鐘腳踩大小端模式——C語言進(jìn)階

    摘要:我們常用的結(jié)構(gòu),就是小端模式,什么則為大端模式?jīng)]學(xué)我也不知道是個(gè)啥,但還是擺出來。 目錄 傳統(tǒng)藝能?過渡區(qū)?正片開始?共用體原理?字節(jié)順序?大小端存儲(chǔ)?共用體判斷...

    andong777 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<