一篇文章帶你了解C語(yǔ)言操作符
操作符和表達(dá)式
我們?cè)诔跏糃語(yǔ)言已經(jīng)大致了解了操作符,我們今天一起詳細(xì)解剖操作符。
操作符
C語(yǔ)言操作符很多,但大致進(jìn)行分類后,有以下幾種操作符
//算數(shù)操作符 + - * / % //移位操作符 << >> //位操作符 & | //賦值操作符 = += -= *= /= ... //單目操作符 sizeof() ! ++ -- & * //關(guān)系操作符 > >= < <= == //邏輯操作符 && || //條件操作符 ?: //逗號(hào)表達(dá)式 , //其他操作符 [] () -> . ...
算數(shù)操作符
算數(shù)操作符再常見(jiàn)不過(guò),
加減乘除,取余。
+ - * /
操作符和我們數(shù)學(xué)上的一樣。
值得注意的是
/
int c=10/3; c=10.0/3; c=10/3.0; //c結(jié)果為3 (double)c=10.0/3; //能計(jì)算出小數(shù)值
C語(yǔ)言中,/
需要至少一個(gè)操作數(shù)為浮點(diǎn)數(shù),才能使結(jié)果為浮點(diǎn)數(shù),并且記得存在浮點(diǎn)數(shù)中。
%
求余(取模)操作符
只能計(jì)算兩個(gè)整型之間的結(jié)果,結(jié)果也為整型。
移位操作符
這里說(shuō)的移位,指的是移動(dòng)二進(jìn)制位。
有左移,右移操作符。
<<左移操作符
向左移動(dòng)二進(jìn)制位
可以看到二進(jìn)制左移后,a<<1
是a
的2
倍,所以我們可以知道,左移一位,擴(kuò)大2倍。
左移n
位擴(kuò)大2^n
倍。
>>右移操作符
可想而知,右移操作符,也與左移效果類似,二進(jìn)制位向右移動(dòng)一位。
右邊的二進(jìn)制丟棄,右邊的二進(jìn)制位,并不是添像左移操作符一樣添零,需要分情況討論。
移位又分為算數(shù)移位和邏輯移位。
算數(shù)移位就是右移時(shí),左邊添加那一位是需要看二進(jìn)制的符號(hào)位,添加。添加的哪一位和符號(hào)位相同。
邏輯移位就是不管左移還是右移操作,添加哪一位都是添0。
但我們需要移動(dòng)一個(gè)負(fù)數(shù)時(shí),顯然邏輯移位會(huì)改變?cè)瓟?shù)值得正負(fù)。
所以在一般的編譯器下都采用算數(shù)移位。
可以看到右移操作原來(lái)的值縮小了2^n
倍。
注意:左移和右移都要考慮移位后是否會(huì)溢出。
移位操作是針對(duì)移動(dòng)正數(shù)位,
a>>-1
這樣移位錯(cuò)誤,C語(yǔ)言未定義。
位操作符
位操作,有&
(按位與) , |
(按位或),^
(按位異或)~
(按位取反)。
位操作符顧名思義,是針對(duì)二進(jìn)制位的操作,有兩個(gè)操作數(shù)進(jìn)行,二進(jìn)制位進(jìn)行操作運(yùn)算。
這里我們的二進(jìn)制位都是指的補(bǔ)碼,因?yàn)橐粋€(gè)數(shù)以補(bǔ)碼的形式存放在內(nèi)存中。
// 00000000 00000000 00000000 00100010 // 00000000 00000000 00000000 11010110 // & 00000000 00000000 00000000 00000010 // | 00000000 00000000 00000000 11110110 // ^ 00000000 00000000 00000000 11110100
位操作符 | 作用 |
---|---|
& |
兩操作數(shù)二進(jìn)制位都為真(1)結(jié)果為真(1)否者為假(0) |
| |
兩操作數(shù)二進(jìn)制位為假(0)結(jié)果為假(0)否者為真(1) |
^ |
一真(1)一假(0)結(jié)果為真(1),否者為假(0) |
~ |
二進(jìn)制位按位取反,1變0,0變1 |
位操作符的應(yīng)用
//嘗試寫(xiě)一下這個(gè)代碼 include <stdio.h> int main() { int num1 = 1; //00000000 00000000 00000000 00000001 int num2 = 2; //00000000 00000000 00000000 00000010 num1 & num2; // 00000000 00000000 00000000 00000000 num1 | num2; // 00000000 00000000 00000000 00000011 num1 ^ num2; // 00000000 00000000 00000000 00000011 return 0; }
一道面試題小試牛刀
不創(chuàng)建新的變量,實(shí)現(xiàn)兩個(gè)變量的交換。
//方法一 #include<stdio.h> int main() { int a=3; // 00000000 00000000 00000000 00000011 int b=5; // 00000000 00000000 00000000 00000101 a=a^b; // 00000000 00000000 00000000 00000110 b=a^b; // 00000000 00000000 00000000 00000011 a=a^b; // 00000000 00000000 00000000 00000101 }
有趣的一道代碼,利用^按位異或?qū)崿F(xiàn)了兩數(shù)的交換。
^
異或操作符的性質(zhì)
a^a=0;
a^0=a;
經(jīng)常利用這兩條性質(zhì)解題,寫(xiě)出優(yōu)秀的代碼!
//方法二 #include<stdio.h> int main() { int a=3; int b=5; a=a+b; //a=8 b=a-b; // b=3 a=a-b; // a=5 }
求一個(gè)整數(shù)存儲(chǔ)在內(nèi)存中二進(jìn)制1的個(gè)數(shù)
//方法一 #include<stdio.h> int main() { int n=10; int count=0; while(n) { if(n%2==1) { count++; } n>>=1; } printf("輸入二進(jìn)制位1的個(gè)數(shù):%d",count); }
思考上面的代碼是否存在問(wèn)題
當(dāng)n為負(fù)數(shù)時(shí)?
可以看到程序?qū)?huì)一直死循環(huán)下去。
我們優(yōu)化一下!
//方法二 #include<stdio.h> int main() { int i=0; int count=0; int num=-3; for(i=0;i<32;i++) { if((num>>i)&1==1) //移位并且判斷最后一位是否為1 count++; } return 0; }
每次都要進(jìn)行32次循環(huán),我們是否可以再次優(yōu)化一下!
//方法三 #include <stdio.h> int main() { int num = -1; // 10000000 00000000 00000000 00000001 //補(bǔ)碼 11111111 11111111 11111111 11111111 int i = 0; int count = 0;//計(jì)數(shù) while(num) { count++; num = num&(num-1);//丟棄最后一位1 } printf("二進(jìn)制中1的個(gè)數(shù) = %d\n",count); return 0; }
上面這個(gè)代碼是不是很神奇,一般人想不到,這就是代碼的魅力!
賦值操作符
賦值操作符,我們?cè)偈煜げ贿^(guò)了。
我們可以通過(guò)賦值操作符,將一個(gè)變量改變成你想要的值!
#include<stdio.h> int main() { int weight=180; weight=125; //不滿意可以改變 //連續(xù)賦值 int a=13,b=0,c=0; a=b=c=6; //連續(xù)賦值操作缺點(diǎn)不易調(diào)試 }
復(fù)合賦值操作符
+= -= *= /= %= …
可以看到很多復(fù)合賦值操作符
a+=2; ===> a=a+2; a*3; ===> a=a*3; //其他運(yùn)算符一個(gè)道理 ....
這邊是復(fù)合賦值操作符,使用起來(lái)很簡(jiǎn)單,也很方便!
單目操作符
//單目操作符就是只有一個(gè)操作數(shù)的操作符! + - ! sizeof() ++ -- ~ * (類型)
+ -
這里的+ -
都是單目操作符,并不是算數(shù)操作符中的+-
!
a=-5; //-5這里的-指的是單目操作符! b=+5; //+5 +可以省略!
!
邏輯反操作符
while(a!=0) //這里就是!邏輯反操作符 { count++; //a不為0count++; } while(!a) { count++; //a為0count++; }
sizeof
是否感到很詫異,sizeof居然是操作符!
sizeof
是比較特殊的一個(gè)操作符,并不是函數(shù)!
我們知道sizeof可以計(jì)算一個(gè)變量和類型的所占空間內(nèi)存大??!
int main() { int a = -10; int* p = NULL; printf("%d\n", !2); printf("%d\n", !0); a = -a; p = &a; printf("%d\n", sizeof(a)); printf("%d\n", sizeof(int)); printf("%d\n", sizeof a); //這樣寫(xiě)行不行? printf("%d\n", sizeof int);//這樣寫(xiě)行不行? return 0; }
可以看到當(dāng)sizeof計(jì)算一個(gè)類型時(shí),不添加括號(hào),就會(huì)報(bào)錯(cuò),然而計(jì)算一個(gè)變量的大小時(shí)卻可以省略括號(hào)!
總結(jié):sizeof計(jì)算類型所占內(nèi)存大小時(shí),括號(hào)不可省略。sizeof(類型),計(jì)算變量所占內(nèi)存大小時(shí),sizeof(變量),sizeof變量
將錯(cuò)誤更改一下,看一下運(yùn)行結(jié)果!
sizeof和數(shù)組
我們知道sizeof可以計(jì)算變量的空間大小,所以我們經(jīng)常通過(guò)sizeof計(jì)算一個(gè)數(shù)組的元素個(gè)數(shù)!
公式:sizeof(數(shù)組)/sizeof(數(shù)組的一個(gè)元素)
#include <stdio.h> void test1(int arr[]) { printf("%d\n", sizeof(arr));//(2) } 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));//(1) printf("%d\n", sizeof(ch));//(3) test1(arr); test2(ch); return 0; }
問(wèn):
(1)、(2)兩個(gè)地方分別輸出多少?
(3)、(4)兩個(gè)地方分別輸出多少?
我們先通過(guò)自己計(jì)算一下!
計(jì)算結(jié)果!
(1)40 (2) 40 (3)10 (4) 10
而運(yùn)行結(jié)果!
可以看到,運(yùn)行結(jié)果并不是那樣!
我們?cè)谒伎家幌逻@個(gè)結(jié)果,為啥結(jié)果會(huì)是4?
我們明明是將數(shù)組,直接傳參過(guò)去 ,而通過(guò)sizeof計(jì)算的內(nèi)存大小卻不是,難道我們只傳參了一個(gè)地址過(guò)去?
我們調(diào)試一下,發(fā)現(xiàn)就是假設(shè)的這樣,數(shù)組傳參并沒(méi)有將整個(gè)數(shù)組傳參過(guò)去,而是傳參了一個(gè)指針!
而我們?cè)趚86也就是32位平臺(tái)下,指針?biāo)純?nèi)存空間大小為4個(gè)字節(jié)。
++ --
//前置++和--: #include <stdio.h> int main() { int a = 10; int x = ++a; //先對(duì)a進(jìn)行自增,然后對(duì)使用a,也就是表達(dá)式的值是a自增之后的值。x為11。 int y = --a; //先對(duì)a進(jìn)行自減,然后對(duì)使用a,也就是表達(dá)式的值是a自減之后的值。y為10; return 0; } //后置++和-- #include <stdio.h> int main() { int a = 10; int x = a++; //先對(duì)a先使用,再增加,這樣x的值是10;之后a變成11; int y = a--; //先對(duì)a先使用,再自減,這樣y的值是11;之后a變成10; return 0; }
總結(jié): 前置++,--先進(jìn)行自加操作,再使用!
后置++,--先使用再進(jìn)行自加操作!
關(guān)系操作符
> >= < <= == (判斷是否等于) !=(判斷不等于)
這些這是基本的關(guān)系操作符!
我們已經(jīng)很常見(jiàn)了,我們看一下關(guān)系操作符的運(yùn)行結(jié)果!
可以看到,當(dāng)判斷結(jié)果為真是,vs用1代表真,用0代表假。
注意:我們?cè)跍y(cè)試,結(jié)果是否相等時(shí),用==而不是賦值操作符=。
邏輯操作符
邏輯操作符,有邏輯與&&,邏輯或||
當(dāng)我們要測(cè)試兩個(gè)表達(dá)式結(jié)果時(shí),如果要同時(shí)滿足,使用邏輯與&&只需滿足其中一個(gè)表達(dá)式結(jié)果時(shí)使用邏輯或||
我們要區(qū)分邏輯操作符和位操作符按位與&,按位或|區(qū)別!
#include<stdio.h> int main() { int a=3;//00000000 00000000 00000000 00000011 int b=1;//00000000 00000000 00000000 00000001 printf("%d\n",a&b); printf("%d\n",a|b); printf("%d\n",a&&b); printf("%d\n",a||b); return 0; }
位操作符和邏輯操作符截然不同,一個(gè)是對(duì)整數(shù)的二進(jìn)制進(jìn)行操作,另一個(gè)是對(duì)表達(dá)式的結(jié)果進(jìn)行判斷!
&&
只有當(dāng)兩個(gè)表達(dá)式結(jié)果同時(shí)為真,結(jié)果才為真!
||
只有當(dāng)兩個(gè)表達(dá)式結(jié)果同時(shí)為假,結(jié)果才為假!
邏輯表達(dá)式的特性!
#include<stdio.h> int main() { int a=3,b=5,c=6,i=0; i=a++&&++b; printf("%d %d\n",a,b); i=a++||++b; printf("%d %d\n",a,b); return 0; }
我們可以看到,邏輯或||第二個(gè)表達(dá)式,并沒(méi)有執(zhí)行。
這是為什么呢!
總結(jié): 邏輯與&&當(dāng)執(zhí)行到表達(dá)式結(jié)果為假,便停止執(zhí)行,后面的表達(dá)式!
邏輯或||當(dāng)執(zhí)行到表達(dá)式結(jié)果為真,便停止執(zhí)行后面的表達(dá)式!
這就是我們常說(shuō)的邏輯短路特點(diǎn)!
條件操作符
exp1 ? exp2 : exp3
條件操作符通常由3個(gè)表達(dá)式構(gòu)成!又叫(三目操作符)!
如果exp1表達(dá)式結(jié)果為真,執(zhí)行exp2,否者執(zhí)行exp3
可以看到與我們的判斷語(yǔ)句if類似!
#include<stdio.h> int main() { int a=5,b=3,max=0; //if判斷語(yǔ)句求最大值 if(a>b) { max=a; } else { max=b; } //條件表達(dá)式 a>b?max=a:max=b; return 0; }
可以看到條件表達(dá)式的優(yōu)點(diǎn),可以大大的簡(jiǎn)化代碼!
逗號(hào)表達(dá)式
exp1,exp2,exp3...expN
表達(dá)式之間用,分隔開(kāi),這就是逗號(hào)表達(dá)式。
表達(dá)式特點(diǎn)
#include<stdio.h> int main() { int a=2,b=3,c=5; int i=(a++,b++,c); printf("a=%d b=%d c=%d i=%d",a,b,c,i); return 0; }
可以看到表達(dá)式i=(a++,b++,c);結(jié)果i=5也就是最后一個(gè)表達(dá)式c的值。
逗號(hào)表達(dá)式運(yùn)算特點(diǎn):
表達(dá)式從左往右依次計(jì)算,最后一個(gè)表達(dá)式的值,便是整個(gè)逗號(hào)表達(dá)式結(jié)果的值!
其他操作符
[]下標(biāo)引用操作符 ()函數(shù)調(diào)用操作符 . ->結(jié)構(gòu)成員訪問(wèn)操作符
[]下標(biāo)引用操作符
操作數(shù):一個(gè)數(shù)組名+一個(gè)索引值
int arr[10];//創(chuàng)建數(shù)組 arr[9] = 10;//實(shí)用下標(biāo)引用操作符。 // [ ]的兩個(gè)操作數(shù)是arr和9。
既然是兩個(gè)操作數(shù),那么兩個(gè)操作數(shù)可以交換位置嗎?
可以看到arr[9]等價(jià)9[arr]
但是我們并不介意用9[arr]
()函數(shù)調(diào)用操作符
( ) 函數(shù)調(diào)用操作符
接受一個(gè)或者多個(gè)操作數(shù):第一個(gè)操作數(shù)是函數(shù)名,剩余的操作數(shù)就是傳遞給函數(shù)的參數(shù)。
#include <stdio.h> void test1() { printf("hehe\n"); } void test2(const char *str) { printf("%s\n", str); } int main() { test1();//實(shí)用()作為函數(shù)調(diào)用操作符。 test2("hello bit.");//實(shí)用()作為函數(shù)調(diào)用操作符。 return 0; }
. :結(jié)構(gòu)體.成員名
->:結(jié)構(gòu)體指針->成員名
#include <stdio.h> struct Stu { char name[10]; int age; char sex[5]; double score; }; void set_age1(struct Stu stu) { stu.age = 18; } void set_age2(struct Stu* pStu) { pStu->age = 18;//結(jié)構(gòu)成員訪問(wèn) } int main() { struct Stu stu; struct Stu* pStu = &stu;//結(jié)構(gòu)成員訪問(wèn) stu.age = 20;//結(jié)構(gòu)成員訪問(wèn) set_age1(stu); pStu->age = 20;//結(jié)構(gòu)成員訪問(wèn) set_age2(pStu); return 0; }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C語(yǔ)言中實(shí)現(xiàn)協(xié)程案例
這篇文章主要介紹了C語(yǔ)言中實(shí)現(xiàn)協(xié)程案例,本文通過(guò)將協(xié)程與線程和異步回調(diào)進(jìn)行對(duì)比,以及具體實(shí)現(xiàn)案例,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C++實(shí)現(xiàn)LeetCode(94.二叉樹(shù)的中序遍歷)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(94.二叉樹(shù)的中序遍歷),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語(yǔ)言中g(shù)etchar()的返回類型為什么是int詳解
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中g(shù)etchar()的返回類型為什么是int的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11Sublime Text 3 實(shí)現(xiàn)C++代碼的編譯和運(yùn)行示例
下面小編就為大家?guī)?lái)一篇Sublime Text 3 實(shí)現(xiàn)C++代碼的編譯和運(yùn)行示例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09Dev C++編譯時(shí)運(yùn)行報(bào)錯(cuò)source file not compile問(wèn)題
這篇文章主要介紹了Dev C++編譯時(shí)運(yùn)行報(bào)錯(cuò)source file not compile問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01C++實(shí)現(xiàn)字符格式相互轉(zhuǎn)換的示例代碼
這篇文章主要為大家詳細(xì)介紹了C++中實(shí)現(xiàn)字符格式相互轉(zhuǎn)換的方法,主要有UTF8與string互轉(zhuǎn)、wstring與string互轉(zhuǎn),感興趣的小伙伴可以了解一下2022-11-11