C语言操作符详解
?作者簡介:嵌入式入坑者,與大家一起加油,希望文章能夠幫助各位!!!!
 📃個人主頁:@rivencode的個人主頁
 🔥系列專欄:玩轉(zhuǎn)C語言
 💬推薦一款模擬面試、刷題神器,從基礎(chǔ)到大廠面試題👉點(diǎn)擊跳轉(zhuǎn)刷題網(wǎng)站進(jìn)行注冊學(xué)習(xí)
目錄
- 前言
- 一.深度理解取余/取模運(yùn)算
- 二.續(xù)行符與轉(zhuǎn)義字符
- 三.邏輯運(yùn)算符
- 四.位操作符
- 1. 按位與 按位或 按位取反
- 2.移位操作符
- 實(shí)戰(zhàn)(重點(diǎn))
 
- 五.深入理解 a++
- 六.操作符優(yōu)先級
前言
所有關(guān)于運(yùn)算的操作符,不管是邏輯運(yùn)算還是位運(yùn)算,都是先將變量在內(nèi)存中提取在CPU內(nèi)存寄存器中進(jìn)行運(yùn)算,然后計算的結(jié)果在寫回內(nèi)存,所以我們操作的都是補(bǔ)碼,因?yàn)閮?nèi)存中存儲的都是數(shù)據(jù)的補(bǔ)碼,只有我們打印某個數(shù)據(jù)時才會涉及到原碼的概念。
 建議在學(xué)習(xí)運(yùn)算操作符之前先明白數(shù)據(jù)(整形)在內(nèi)存中如何存儲
 《數(shù)據(jù)到底在內(nèi)存中如何存儲》
一.深度理解取余/取模運(yùn)算
 對于 / 操作符如果兩個操作數(shù)都為整數(shù),執(zhí)行整數(shù)除法。而只要有浮點(diǎn)數(shù)執(zhí)行的就是浮點(diǎn)數(shù)除法。
想要得到小數(shù)部分一定一個操作數(shù)得是浮點(diǎn)數(shù)
% 操作符的兩個操作數(shù)必須為整數(shù)。返回的是整除之后的余數(shù)。
 
1.第一個問題整數(shù)的除法是如何取整的
 
 為什么是這樣的一種取整方式呢。
 
 其實(shí)C語言中的默認(rèn)取整方式是向零取整
向零取整的函數(shù)
 
 
 向負(fù)無窮方向取整的函數(shù),返回不大于x的最大整數(shù)值
 
 
 向正無窮方向取整的函數(shù),返回不小x的最小整數(shù)值
 
 
 
 四舍五入取整
 
 
 取整方案對比:
 
 
 這里你會發(fā)現(xiàn)就算不同的取整方式可能會得到同樣的值。
重點(diǎn)來了:取模和取余一樣嘛
先說結(jié)論
本質(zhì) 1 取整:
 取余:盡可能讓商,向零取整
 取模:盡可能讓商,向-∞方向取整
而我們前面已經(jīng)說了C語言默認(rèn)的取整方案為向零取整,所以C語言中的%運(yùn)用其實(shí)是在取余數(shù)。
被除數(shù)、除數(shù)、商、余數(shù)的關(guān)系:
如果a和d是兩個自然數(shù),d非零,可以證明存在兩個唯一的整數(shù) q 和 r,滿足 a = q*d + r 且0 ≤ |r|< |d|。。其中,q被稱為商,r 被稱為余數(shù)。
 接下來來一個怪一點(diǎn)的:-10%3=?
在VS2013編譯器中:
 
在Python 2.7.12
 
 為什么會出現(xiàn)不同的結(jié)果呢
根本原因是
 C語言中 % 是取余數(shù) — 得出的商向零取 整
 Python中% 是取模 — 得出的商向負(fù)無窮取整
這樣我們就能解釋了,我們知道了商知道被除數(shù)和除數(shù)就可以求出余數(shù)
 r余數(shù)的大小是取決于商的,而商的大小有取決與取整方式:
對任何一個大于0的數(shù),對其進(jìn)行0向取整和-∞取整,取整方向是一致的。故取模等價于取余
對任何一個小于0的數(shù),對其進(jìn)行0向取整和-∞取整,取整方向是相反的。故取模不等價于取余
這句是為什么C語言中通常將取余等價與取模,原因就是我們通常都是正數(shù),而正數(shù)的取余才真正等價于取模。
同符號數(shù)據(jù)相除,得到的商,一定是正數(shù)(正數(shù)vs正整數(shù)),即大于0!=在對其商進(jìn)行取整的時候,不管是向零取整還是向負(fù)無窮取整取整的方向都是一樣的所以所得的商也一樣,余數(shù)也一樣,所以取模等價于取余。
同符號時:取模等價于取余
 
 不同符號時所得的商一定是負(fù)數(shù),取模向負(fù)無窮取整,取余是向零取整則取整方向不一樣,所以所得的商不一樣,所得的余數(shù)也不一樣。
二.續(xù)行符與轉(zhuǎn)義字符
注意:續(xù)航符的后面不能帶任何東西(包括空格)
 
- \的轉(zhuǎn)義功能:
 
 
 
 一道面試題:
 
 解析:
 
 
 
\0 與 數(shù)值0,NULL,和字符零’0’的區(qū)別
 
 
 *NULL的數(shù)值其實(shí)是零,只不過NULL的類型是 void 類型
 \0的ACSLL值也就是十進(jìn)制表示也為0, 只不過\0的類型為字符型。
 而 '0’字符零是ACSLL值為48 .
總結(jié):\0 與 數(shù)值0,NULL數(shù)值相同都為0類型不同,
- 回車與換行
 
 回車與換行本質(zhì)是兩個概念:
 回車:光標(biāo)回到當(dāng)前行的最開始
 換行:光標(biāo)移動到下一行
只不過 \n 既回車又換行。
利用回車做一個小程序:旋轉(zhuǎn)光標(biāo):
 
 因?yàn)槲覀兲砑恿?\r,所以每次打印都回到當(dāng)前行的最開始覆蓋上一次的打印
利用回車做一個小程序:倒計時:
 
 因?yàn)槲覀兲砑恿?\r,所以每次打印都回到當(dāng)前行的最開始覆蓋上一次的打印
三.邏輯運(yùn)算符
&& 邏輯與
 || 邏輯或
邏輯與的特點(diǎn):
 1.所有表達(dá)式都成立才成立
 2.從左向右結(jié)合
 3.若有一個表達(dá)式不成立則后面的表達(dá)式不執(zhí)行
所有表達(dá)式成立才成立:
 
 若有一個表達(dá)式不成立則后面的表達(dá)式不執(zhí)行:
 
 注意:
 這里成立與不成立的感念是真假的概念:非0為真,0為假
邏輯或的特點(diǎn):
 1.所有表達(dá)式有一個成立則成立
 2.從左向右結(jié)合
 3.若有一個表達(dá)式成立則后面的表達(dá)式不執(zhí)行
 都不成立才不成立:所有表達(dá)式全部執(zhí)行一遍
 
筆試題:
 
解析:
 
 變式1:
 
 解析:
 
四.位操作符
1. 按位與 按位或 按位取反
所謂雙目運(yùn)算符:有兩個操作數(shù),操作數(shù)必須是整數(shù)
所有的運(yùn)算都是要經(jīng)過CPU來執(zhí)行的,執(zhí)行的過程中要想內(nèi)存中提取數(shù)據(jù),而存儲在內(nèi)存中的數(shù)據(jù)全是補(bǔ)碼,所以我們的運(yùn)算全是針對與數(shù)據(jù)的補(bǔ)碼
按位與運(yùn)算 &
 按位與運(yùn)算符"&"是雙目運(yùn)算符。 其功能是參與運(yùn)算的兩數(shù)各對應(yīng)二進(jìn)制位相與。只有對應(yīng)的兩個二進(jìn)制位均為1時,結(jié)果位才為1 ,否則為0。
 
按位或運(yùn)算 |
 按位或運(yùn)算符“|”是雙目運(yùn)算符。 其功能是參與運(yùn)算的兩數(shù)各對應(yīng)的二進(jìn)制位相或。只要對應(yīng)的二個二進(jìn)制位有一個為1時,結(jié)果位就為1。
 求反運(yùn)算~
 求反運(yùn)算符~為單目運(yùn)算符,具有右結(jié)合性。 其功能是對參與運(yùn)算的數(shù)的各二進(jìn)位按位求反。
 
 注意:符號位照樣取反
按位異或運(yùn)算 ^
 按位異或運(yùn)算符“^”是雙目運(yùn)算符。 其功能是參與運(yùn)算的兩數(shù)各對應(yīng)的二進(jìn)制位相異或,當(dāng)兩對應(yīng)的二進(jìn)制位相異時結(jié)果為1,相同結(jié)果為0,
 
按為異或的特點(diǎn):
 最好能記住解題塊的很
 性質(zhì):
 1.交換律 a^ b = b^a
 2.結(jié)合律 a^ b ^ c = a^ (b^c)
 3.任何數(shù)后零異或都是它本身
 4. 自身與自身異或?yàn)?
其實(shí)上面的特點(diǎn)很好證明只要記住:相同為0,相異為1
實(shí)戰(zhàn):交換兩個數(shù)
1.創(chuàng)建臨時變量
 
 2. 不創(chuàng)建臨時變量
 
 缺陷:當(dāng)兩個數(shù)的足夠大時相加可能會溢出
 3. 異或
 
 
 
 其實(shí)知道異或的特性很快能做出來
2.移位操作符
左移: 最高位丟棄,最低位補(bǔ)零
 右移:
 1.無符號數(shù):最低位丟棄,最高位補(bǔ)零[邏輯右移]
 2.有符號數(shù):最低位丟棄,最高位補(bǔ)符號位[算術(shù)右移]
注意:
 有無 符號看的是數(shù)據(jù)的類型,與內(nèi)存中保存的數(shù)據(jù)無關(guān)
左移: 最高位丟棄,最低位補(bǔ)零
 
 右移:
 1.無符號數(shù):最低位丟棄,最高位補(bǔ)零[邏輯右移]
 2.有符號數(shù):最低位丟棄,最高位補(bǔ)符號位[算術(shù)右移]
 
如何理解丟棄:
 左移或者右移都是計算,都要在CPU中進(jìn)行,可是參與移動的變量,是在內(nèi)存中的。所以需要先把數(shù)據(jù)移動到CPU內(nèi)寄存器中,在進(jìn)行移動,實(shí)際移動的過程中,是在寄存器中進(jìn)行的,即大小固定的單位內(nèi)。那么,左移右移一定會有位置跑到"外邊"的情況
所以還有一個結(jié)論:
 我們左移右移都是針對內(nèi)存中的數(shù)據(jù)而言的,而內(nèi)存中的存儲的數(shù)據(jù)的補(bǔ)碼。
到底什么時候需要原碼:只有我們在打印某個數(shù)據(jù)時,從內(nèi)存中拿出來的時候。
實(shí)戰(zhàn)(重點(diǎn))
設(shè)置數(shù)據(jù)的指定比特位為1,其他比特位不變
 
 
設(shè)置數(shù)據(jù)的指定比特位為0,其他比特位不變
 
 
顯示數(shù)據(jù)的所有比特位,并記比特位中有多少個1
void ShowBits(int n) {int count = 0;int num = sizeof(n) * 8 - 1;while (num>=0){if (n&(1<<num)){printf("%d ",1);count++;}else{printf("%d ", 0);}num--;}printf("\n");printf("1的個數(shù):%d\n", count); }實(shí)驗(yàn)效果:
 
 
 左移:一般情況下左移一位就乘以2
 右移:一般情況下右移一位就除以2
 
 這個我就不分析了, 與左移類似。
特殊情況:-1右移還是-1因?yàn)樽罡呶谎a(bǔ)的是符號位
 
重點(diǎn)理解右移:
 注意:
 有無 符號看的是數(shù)據(jù)的類型,與內(nèi)存中保存的數(shù)據(jù)無關(guān)
 
 
 如果對整形如何存儲在內(nèi)存中,或者對無符號類型的變量為什么能存儲負(fù)數(shù)有疑問請看——<數(shù)據(jù)到底在內(nèi)存中如何存儲>
移位一個要注意的點(diǎn):
 +號的優(yōu)先級比 移位操作符要高
 
 
 有先級的概念一定要注意:拿捏不準(zhǔn)就加上括號,準(zhǔn)沒錯
五.深入理解 a++
a++ 在任何情況下都是先使用后++嘛
答案是否定的:
當(dāng)有a++被使用時:
 確實(shí)是先使用然后在完成自增
 
當(dāng)有a++沒有被使用時:
 a直接自增
 
 接下來看一段復(fù)雜代碼:
 
在VS2013編譯器中:
 
 在linux下gcc編譯器中:
 
 為什么同一份代碼在不同的編譯器下,結(jié)果不同呢
 vs2013 -->12
 gcc —>10
根本原因?qū)懗鲞@種代碼:計算的途徑有很多種
- vs2013 -->12
 根本原因是編譯器先將i自增3次在指向i的相加
 怎么計算方式并沒有違反操作符的優(yōu)先級與結(jié)合性的規(guī)則
優(yōu)先級:只會影響到兩個相鄰的操作符先執(zhí)行哪個
- gcc —>10
 相當(dāng)于先執(zhí)行前面i++ ,讓i自增兩次i變成3,然后在執(zhí)行前面兩個i相加 得3+3得6,最后讓最后一個i++,i變成4,最后相加的3+3+4=10
看完了匯編是不是還是有點(diǎn)沒理解:
 其實(shí)這個式子與我們?nèi)粘?shù)學(xué)中的一個式子差不多:
 
- 貪心法
C語言有這樣一個規(guī)則:每一個符號應(yīng)該包含盡可能多的字符。也就是說,編譯器將程序分解成符號的方法是,從左到右一個一個字符的讀人,如果該字符可能組成一個符號,那么再讀人下一個字符時,判斷已經(jīng)讀人的兩個字符組成的字符串是否可能是一個符號的組成部分;如果可能,繼續(xù)讀入下一個字符,重復(fù)上述判斷,直到讀人的字符組成的字符串已不再可能組成一個有意義的符號。這個處理的策略被稱為“貪心法”。需要注意的是,除了字符串與字符常量,符號的中間不能嵌有空白(空格、制表符、換行符等),比如:== 是單個符號,而= =是兩個等號。
 
 貪心法簡單點(diǎn)說就是:盡可能多的匹配符號,組成C語言中多字符符號,例如:++ – &= <<= … 所以寫這些符號中間不要添加空格
看一個例子就明白了:
六.操作符優(yōu)先級
復(fù)雜表達(dá)式的求值有三個影響的因素。
 1. 操作符的優(yōu)先級
 2. 操作符的結(jié)合性
 L-R :從左向右
 R-L :從右向左
 3. 是否控制求值順序。
 邏輯或 || 邏輯與 && 條件操作符 ? : 逗號表達(dá)式
兩個相鄰的操作符先執(zhí)行哪個取決于他們的優(yōu)先級。如果兩者的優(yōu)先級相同,取決于他們的結(jié)合性。
操作符優(yōu)先級,越上面優(yōu)先級越高
 
 條件操作符:
 格式:
 如果表達(dá)式1為真,則執(zhí)行表達(dá)式2,表達(dá)式2是整個表達(dá)式的結(jié)果
 如果表達(dá)式1不成立,則執(zhí)行表達(dá)式3,表達(dá)式3是整個表達(dá)式的結(jié)果
舉例:求兩個數(shù)的較大值
 
 其實(shí)也可以實(shí)現(xiàn)嵌套,在某個表達(dá)式又搞一個 exp1? exp2:exp3
- 逗號表達(dá)式
 逗號表達(dá)式,就是用逗號隔開的多個表達(dá)式。
 逗號表達(dá)式,從左向右依次執(zhí)行。整個表達(dá)式的結(jié)果是最后一個表達(dá)式的結(jié)果。
總結(jié)
 
                            
                        - 上一篇: 信息安全密码学:DES算法的核心 E盒、
- 下一篇: FTP的主动模式和被动模式
