摘要:操作符的兩個操作數必須為整數。函數調用用作為函數調用操作符。訪問一個結構的成員結構體成員名結構體指針成員名還是熟悉的栗子在之前的博客請回答語言初識語言下入門的結構體出現過的栗子名字圖鑒編號身高重量屬性類型
學習操作符之前我們先對操作符分類,還和之前的初始c語言中一樣
+ - * / %
算數操作符本身很簡單,不過有幾個注意事項
%
操作符之外,其他的幾個操作符可以作用于整數和浮點數。/
操作符如果兩個操作數都為整數,執行整數除法。而只要有浮點數執行的就是浮點數除法。%
操作符的兩個操作數必須為整數。返回的是整除之后的余數。 int ret= 10 % 3;//% -- 取模(余) int ret = 10 / 3;//除法 -- 商 //當 /兩端都是整數的時候,執行的都是整數的除法,兩端只要有一個是浮點數,執行的就是浮點數的除法 double ret2 = 10 / 3.0;//想得到小數,必須保證除數或者被除數里面至少有一個是浮點數
移位操作符這里就涉及了把一個整數化為二進制位,每一位的權重相當于2的1次方,相當于假如有四個1,則1 1 1 1每個1都表示不同的權重
第4位 | 第3位 | 第2位 | 第1位 |
---|---|---|---|
8 | 4 | 2 | 1 |
此外我們還得搞清楚整數的三種二進制表達形式
原碼
反碼
補碼
對于整數的3種形式我們有這樣一個結論:
下面對一個整數5來舉例
再對-5來舉例
從這個例子我們可以看到
原碼在第32位中的0和1用來表示符號位,0表示正數,1表示負數,反碼同樣
反碼相當于原碼的符號位不變,其他位按位取反得到的就是反碼
補碼就是反碼最低位+1
用VS調試看內存我們就可以直觀看到
這里的ffff
就是16進制的-1也就是二進制下32個1,因為16進制下一個f
相當于15,因此說明內存存儲的方式是利用補碼
總結一下:
- 一個整數在被存入內存時,存儲方式是利用的補碼
- 打印或者使用的時候,利用的是原碼
為什么這么規定呢?這涉及到加法器和減法器的原理,后面再展開
移位規則:
- 左邊拋棄、右邊補0
int main(){ int a = 5; int b = a << 2; printf("%d/n",a); printf("%d/n", b); return 0;}
注:當然a是不會被改變的
再舉個負數的例子:
int main(){ int a = -5; int b = a << 2; printf("%d/n",a); printf("%d/n", b); return 0;}
負數左移之后,打印出來是多少?
過程是先把-5補碼左移2位,然后按照負數的規律轉換成原碼,打印的時候是打印原碼結果
移位規則:
有點不同,稍微復雜
首先我們思考一下右移運算本身分兩種:
左邊用0填充,右邊丟棄
左邊用原該值的符號位填充,右邊丟棄
到底如何移動,取決于編譯器的不同,我們常用的編譯器是算術右移
比如說VS2019
注:這里的前提是在VS2019中,也即算術移位的前提下
int main(){ int a = -5; int b = a >> 1; printf("%d/n",a); printf("%d/n", b); return 0;}
具體過程就不細給了,按照規則,和左移稍微有一點區別
注:
對于移位運算符,不要移動負數位,這個是標準未定義的。
int num = 10;num>>-1;//error
已知位操作符有:
& //按位與| //按位或^ //按位異或
注:他們的操作數必須是整數。
問:位操作符用哪種二進制位儲存形式進行運算?
答:因為都是內存運算,所以都是用的補碼
位操作符簡單來說就是兩個整數的每一位之間互相比較
輸入a | 輸入b | 結果 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
0 | 1 | 0 |
1 | 1 | 1 |
看示例
int main(){ int a = 3; int b = -5; int c = a & b; printf("%d", c); return 0;}
輸入a | 輸入b | 結果 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 1 |
int main(){ int a = 3; int b = -5; int c = a | b; printf("%d", c); return 0;}
兩個整數的二進制位互相異或,其中二進制位
相同為0
相異為1
輸入a | 輸入b | 結果 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
int main(){ int a = 3; int b = -5; int c = a ^ b; printf("%d", c); return 0;}
int main(){ int num1 = 1; int num2 = 2; printf("%d/n",num1 & num2); printf("%d/n", num1 | num2); printf("%d/n", num1 ^ num2); return 0;}
不能創建臨時變量(第三個變量),實現兩個數的交換。
3個解法:
int main(){ int a = 3; int b = 5; //1 int c = 0;//臨時變量 printf("交換前: a=%d b=%d/n", a, b); c = a; a = b; b = c; //2 a = a + b; b = a - b; a = a - b; //3 - 異或 a = a ^ b; b = a ^ b;//a ^ b ^ b a = a ^ b;//a ^ b ^ a printf("交換后: a=%d b=%d/n", a, b); return 0;}
可以發現第一個解法不符合要求,因為要創建臨時變量,剩下兩個方法可以巧妙解決,其中第三個方法最為巧妙,巧妙使用異或實現轉換,可以嘗試化成二進制舉例驗證一下
編寫代碼實現:求一個整數存儲在內存中的二進制中1的個數。
想法:
我們說如果由一個數a
&
1,那么就能得出這個數字二進制最低位是0還是1那么如果我循環中不斷<<1再&1就可以計算出一個整數有幾個1
//方法1//解決不了負數#include int main(){ int num = 10; int count = 0;//計數 while (num) { if (num % 2 == 1) count++; num = num / 2; } printf("二進制中1的個數 = %d/n", count); return 0;}//方法2:#include int main(){ int num = -1; int i = 0; int count = 0;//計數 for (i = 0; i < 32; i++) { if (num & (1 << i)) count++; } printf("二進制中1的個數 = %d/n", count); return 0;}//這個方法還能更加優化//方法3:#include int main(){ int num = 0; int i = 0; int count = 0;//計數 scanf("%d", &num); while (num) { count++; num = num & (num - 1); } printf("二進制中1的個數 = %d/n", count); return 0;}//這種方式很好,達到了優化的效果,但是難以想到。
賦值操作符可以改變之前的賦值
int weight = 120;//體重weight = 99;//不滿意就賦值double salary = 10000.0;//工資salary = 20000.0;//使用賦值操作符賦值。
當然,賦值操作符可以連續賦值,但不是很建議這么寫
a=x=y=100;
當然:常量不能賦值
##4.1 復合賦值符
+=-=*=/=%=>>=<<=&=|=^=
這些運算符都可以寫成復合的效果
int x = 0;x = x+10;//普通x += 10;//復合賦值//其他運算符一樣的道理。這樣寫更加簡潔。
已知單目操作符有:
! //邏輯反操作- //負值+ //正值& //取地址sizeof //操作數的類型長度(以字節 為單位)~ //對一個數的二進制按位取反-- //前置、后置--++ //前置、后置++* //間接訪問操作符(解引用操作符)(type) //強制類型轉換
很多在之前的初識c語言中都已經講過,這里挑幾個記一下關鍵點
關于sizeof其實我們之前也已經見過了,可以求變量(類型)所占空間的大小。
常見的使用
有求數組的長度:
int sz=sizeof(arr)/sizeof(arr[0]);
有求數組的大小
int arr[10]= {1,2,3,4,5,6};printf("%d/n",sizeof(arr));//40字節---4*10
有求int類型數組或一個int的大小
printf("%d/n",sizeof(int [10]));//40字節---4*10printf("%d/n",sizeof(int));//4
小栗子:
void test1(int arr[]){ printf("%d/n", sizeof(arr));//(3)}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));//(2) test1(arr); test2(ch); return 0;}
注意從函數中傳過來的是指針,所以
sizeof
測的是 指針變量的大小,而主函數里面測的是整個數組中的大小
~
按位取反int main(){ int a = 0; //~ 按(內存中補碼的2進制)位取反 //00000000000000000000000000000000 //11111111111111111111111111111111 - 補碼 //11111111111111111111111111111110 - 反碼 //10000000000000000000000000000001 - 原碼 --> -1 printf("%d/n", ~a); return 0;}
有多組輸入的時候
while(~scanf("%d%d",&n,&m);
++ --
//++和--運算符//前置++和--int main(){ int a = 10; int x = ++a; //先對a進行自增,然后對使用a,也就是表達式的值是a自增之后的值。x為11。 int y = --a; //先對a進行自減,然后對使用a,也就是表達式的值是a自減之后的值。y為10; return 0;}//后置++和--int main(){ int a = 10; int x = a++; //先對a先使用,再增加,這樣x的值是10;之后a變成11; int y = a--; //先對a先使用,再自減,這樣y的值是11;之后a變成10; return 0;}
注:注意值的變化
關系操作符:
>>=<<=!= ==
小結
還是不要搞錯
=
和==
邏輯操作符有哪些:
&& 邏輯與|| 邏輯或
區分邏輯與和按位與
區分邏輯或和按位或
1&2----->01&&2---->11|2----->31||2---->1
舉個栗子:
int main(){ int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++;//第一次結果 i = a++ || ++b || d++;//第二次結果 printf("a = %d/n b = %d/n c = %d/nd = %d/n", a, b, c, d); return 0;}
- 第一次的結果是:1 2 3 4
因為&&只要前面算出有0就不算后面的執行了,所以a后置加加->a為1,而b和d不執行
int main(){ int i = 0, a = 1, 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;}
倘若這樣一改就是2 3 3 5了
- 第二次的結果是:1 3 3 4
因為算到++b的時候已經是真了,所以d++就不算下去了,于是自增的只有a和b
小結:邏輯操作符只關注真與假
&&在遇到0(假)之后就不算后面的執行了
||肯定是遇到1(真)之后
exp1 ? exp2 : exp3
之前就寫過兩數之間的最大值
max = (a > b ? a : b);
逗號表達式,就是用逗號隔開的多個表達式。
逗號表達式,從左向右依次執行。整個表達式的結果是最后一個表達式的結果。
小栗子
int a = 1;int b = 2;int c = (a>b, a=b+10, a, b=a+1);
應該從左到右依次執行,因為逗號表達式不只是算最后一個逗號里面的語句最后c應該是13
int arr[10];//創建數組arr[9] = 10;//實用下標引用操作符。
比如說我想要打印數組中下標為8的數
int main(){ int arr[10]={1,2,3,4,5,6,7,8,9,10}; printf("%d",arr[7]);//[]體現了下標引用操作符的作用 printf("%d",7[arr]);//一般不用,沒用的小知識增加了 return 0;}
計算機在計算的時候是arr[7]->*(arr+7)->7[arr]
所以7[arr]也能符合要求
void test1(){ printf("函數調用test1()/n");}void test2(const char* str){ printf("%s/n", str);}int main(){ test1(); //用()作為函數調用操作符。 test2("Strength in Numbers");//用()作為函數調用操作符。 return 0;}
.
結構體.成員名
->
結構體指針->成員名
還是熟悉的栗子:
在之前的博客請回答c語言-初識c語言(下)【入門】的17.結構體出現過的栗子
struct Pokemon{ char name[20];//名字 int id;//圖鑒編號 float height; //身高 float weight;//重量 char fighting_type[20]; //屬性 char species[15]; //類型};int main(){ struct Pokemon pikachu = { "Pikachu",25
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/123362.html
摘要:盡管如此,還具有高級的數據類型和靈活性。它配備了大量的標準模塊,可用于程序庫。一些模塊提供如下功能通過這些很贊的特性,瞬時化身為面向過程的語言。開發者可以便捷地將解釋器連接到一個使用編寫的應用程序,并能隨時用作擴展。下一部分會繼續分享。 【編者按】本文作者是 Abhishek Jaiswal ,擅長 .NET、C#、Python 等多種語言的技術控。本文中,作者通過活潑有趣的口吻向大家...
摘要:年月宣布支持時間延長到年。更詳細的發布列表參閱官網的版本號分為三段,形如。其中表示大版本號,一般當整體重寫,或出現不向后兼容的改變時,增加表示功能更新,出現新功能時增加表示小的改動如修復了某個,只要有修改就增加。年公司正式發布。 < 返回索引頁 Python語言簡介 Python介紹及發展 介紹 Python 官方網站:https://www.python.org/, 大家可以到此處下...
摘要:有超過億用戶,可謂是程序員解惑神站。問答小組允許成員提問并回答其它成員提出的問題,很像。是新手學習和編程的理想網站。目前有萬多注冊用戶,幫助程序員度過關卡。是開發人員的社交網站,是一個適合查詢各種編程語言和實戰技術的網站。 ...
摘要:如果在學習過程中有什么問題可以關注我公眾號琉憶編程庫給我留言。有興趣可以深入學習最后附上學習的知識結構圖譜,可以按著下面的這個知識結構圖進行學習不一定完整,更多資料,面試題,都可以關注公眾號琉憶編程庫獲取。 你好,是我——琉憶。PHP程序員面試系列圖書作者。 作為一名PHP開發者過來人,也是經歷了菜鳥到老手的過程,在此給那些想學PHP的同學指條路,即使你是轉行學PHP一樣可以學會PHP...
閱讀 2312·2021-11-15 11:38
閱讀 2439·2021-11-15 11:37
閱讀 2542·2021-08-24 10:00
閱讀 2900·2019-08-30 15:56
閱讀 1259·2019-08-30 15:53
閱讀 3694·2019-08-29 18:43
閱讀 2929·2019-08-29 17:01
閱讀 3254·2019-08-29 16:25