目錄
一、操作符的分類
二、二進制和進制轉換
(一)概念
(二)二進制
(三)進制轉換
1、2進制與10進制的互換
(1)2進制轉化10進制
(2)10進制轉化2進制
2、2進制與8進制的轉換? ? ? ?
3、2進制與16進制的轉換
三、原碼、反碼、補碼
四、位移操作符
(一)左移操作符
(二)右移操作符
五、位操作符
六、單目操作符
七、逗號表達式
八、下標訪問符、函數調用符
(一)下標訪問符 [ ]
(二)函數調用符 ( )
九、結構成員訪問操作符
(一)結構體
1、概念
2、結構的聲明、定義、初始化
(1)聲明
(2)定義?
(3)初始化
(二)結構體成員訪問操作符
1、結構體成員的直接訪問
2、結構體成員的間接訪問
十、操作符的屬性
(一)優先級
(二)結合性
十一、表達式求值細節
(一)整型提升
1、概念
2、如何整型提升
(二)算術轉換
一、操作符的分類
- 算術操作符: 【+ 、- 、* 、/ 、%】
- 移位操作符: 【<< 、>>】
- 位操作符: 【&、 | 、^】
- 賦值操作符: 【= 、+= 、 -= 、 *= 、 /= 、%= 、<<= 、>>= 、&= 、|= 、^=】
- 單?操作符:【 !、++、--、&、*、+、-、~ 、sizeof、(類型)】
- 關系操作符: 【> 、>= 、< 、<= 、 == 、 !=】
- 邏輯操作符: 【&& 、||】
- 條件操作符:【?? : 】
- 逗號表達式: 【?, 】
- 下標引?:【?[ 下標 ] 】
- 函數調?:【?() 】
- 結構成員訪問:【?. 、->】
? ? ? ? 其中,移位操作符,移動的是二進制位;位操作符,也是使用二進制位進行計算
?
二、二進制和進制轉換
(一)概念
????????我們經常能聽到【2進制、8進制、10進制、16進制】這樣的講法,其實【2進制、8進制、10進制、16進制】是數值的不同表示形式而已,如:
14的2進制:111014的8進制:1614的10進制:1414的16進制:E
? ? ? ? 注意:
????????開頭為【0】的數字,才會被認為是八進制的數字;
????????開頭為【0x】的數字,才會被認為是十六進制
(二)二進制
? ? ? ? 重點介紹一下二進制:
????????首先我們還是得從10進制講起,其實10進制是我們?活中經常使用的,我們已經形成了很多嘗試:
? ? ? ? ① 10進制中滿10進1
? ? ? ? ② 10進制的每一位數字都是由0~9的數字組成的
? ? ? ? 二進制也一樣:
? ? ? ? ① 2進制中滿2進1
? ? ? ? ② 2進制的數字每一位數字都是由0~1的數字組成
(三)進制轉換
1、2進制與10進制的互換
(1)2進制轉化10進制
????????其實10進制的123表示的值是?百??三,為什么是這個值呢?其實10進制的每?位是有權重的,10進制的數字從右向左是個位、?位、百位....,分別每?位的權重是10的0次方 , 10的1次方 , 10的2次方...
? ? ? ? 如下圖:
????????
????????2進制和10進制是類似的,只不過2進制的每?位的權重,從右向左是: 2的0次方 , 2的1次方 , 2的2次方...2進制數值乘以每一位的權重再相加的值為10進制的數值表示
? ? ? ? 以1101為例子,如圖所示:
(2)10進制轉化2進制
2、2進制與8進制的轉換? ? ? ?
????????8進制的數字每一位是0~7,0~7的數字,各?寫成2進制,最多有3個2進制位就足夠了,比如7的?進制是111,所以在2進制轉8進制數的時候,從2進制序列中右邊低位開始向左每3個2進制位會換算?個8進制位,剩余不夠3個2進制位的直接換算
????????如:2進制的 01101011,換成8進制:0153【0開頭的數字,會被當做8進制】
? ? ? ? 2進制轉8進制:2進制從后向前數,每三位2進制換成8進制的一位
????????8進制轉2進制:8進制從后向前數,每一位8進制換成三位2進制
3、2進制與16進制的轉換
????????16進制的數字每?位是0~9, a~f ,0~9, a~f的數字,各自寫成2進制,最多有4個2進制位就足夠了,比如 f 的?進制是1111,所以在2進制轉16進制數的時候,從2進制序列中右邊低位開始向左每4個2進制位會換算?個16進制位,剩余不夠4個?進制位的直接換算
????????如:2進制的01101011,換成16進制:0x6b【0x開頭的數字,才會被當做16進制】
????????2進制轉16進制:2進制從后向前數,每四位2進制換成16進制的一位
????????16進制轉2進制:16進制從后向前數,每一位16進制換成四位2進制
三、原碼、反碼、補碼
? ? ? ? 【整數】的二進制有三種表現形式:原碼,反碼,補碼;
????????【有符號整型 int 】的三種表示方法均有【符號位】和【數值位】,二進制最高一位是【符號位】,其余都是【數值位】;【符號位】:0表示“正”,1表示“負”;
????????【無符號整型 unsight int 】只表示大于等于0的數,所以沒有【符號位】,32個bit位全是【數值位】;
? ? ? ? 【正整數】的原、反、補碼都相同;
? ? ? ? 【負整數】的三種表示方法各不相同
? ? ? ? 【原碼】:直接將數值按照正負數的形式翻譯成?進制得到的就是原碼
? ? ? ? 【反碼】:將原碼的符號位不變,其他位依次按位取反就可以得到反碼
? ? ? ? 注:對于整形來說,數據存放內存中其實存放的是補碼
????????因為:
????????在計算機系統中,數值?律用補碼來表示和存儲。原因在于,使用補碼,可以將符號位和數值域統?處理;同時,加法和減法也可以統?處理(CPU只有加法器)此外,補碼與原碼相互轉換,其運算過程是相同的,不需要額外的硬件電路
四、位移操作符
????????位移操作符,移動的是【存儲在內存中的二進制位(補碼)】
????????<< 左移操作符
????????>> 右移操作符
????????注:移位操作符的操作數只能是【整數】
(一)左移操作符
????????移位規則:左邊拋棄、右邊補0
#include <stdio.h>int main()
{int n = num<<1;printf("n= %d\n", n);printf("num= %d\n", num);return 0;
}
? ? ? ? 注:
????????num的值是放到寄存器里面計算的,計算過后num的值不變
????????左移【一位】有【×2】的效果
(二)右移操作符
????????移位規則:?先右移運算分兩種:
- 邏輯右移:左邊用0填充,右邊丟棄
- 算術右移:左邊用原該值的符號位填充,右邊丟棄
????????右移用的是邏輯右移還是算術右移,取決于編譯器,通常采用的是算數右移;
????????右移【一位】有【÷ 2】的效果
? ? ? ? 如下代碼演示:
#include <stdio.h>int main()
{int num = -1;int n = num>>1;printf("n= %d\n", n);printf("num= %d\n", num);return 0;
}
? ? ? ? 邏輯右移如下:
? ? ? ? 算數右移如下:
? ? ? ? 注意:對于移位運算符,不要移動負數位,這個是標準未定義的,如下:
int num = 10;
num >> -1;
五、位操作符
&? ? ? ? 按位與
|? ? ? ? ? 按位或
^ ????????按位異或
~? ? ? ? ?按位取反
運算規則:
按位與 &:有0則0;同時為1則1
按位或 ?| :有1則1;同時為0則0
按位異或 ^ :同0異1
按位取反 ~ :01互換?
按位異或的特點:
a ^ a = 0;
0 ^ a = a;
a ^ a ^ b = b;
a ^ b ^ a = b;
異或支持交換律
????????
????????一道面試題:不能創建臨時變量(第三個變量),實現兩個整數的交換
#include <stdio.h>int main()
{int a = 10;int b = 20;a = a^b;b = a^b;a = a^b;printf("a = %d b = %d\n", a, b);return 0;
}
????????練習1:編寫代碼實現:求?個整數存儲在內存中的?進制中1的個數
方法一:
#include <stdio.h>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; }
????????進行之前【num模10,num除10】,算一位就消除一位的方法,二進制就【num模2,num除2】
????????缺點:負數無法計算
????????解決:寫成函數的形式,形參為num,設置為無符號整型
方法二:
#include <stdio.h>int main() {int num = -1;int i = 0;int count = 0;//計數for(i=0; i<32; i++){if( num & 1 )count++;num = num >> 1; }printf("二進制中1的個數 = %d\n",count);return 0; }
? ? ? ? 按位與的運算規則為:有0則0,同1才為1;
? ? ? ? 數字1在內存中的二進制只有最后一位是1,其他為0;和1按位與運算只會檢測最后一位是否是1:【num & 1】就可以知道【num】最后一位是不是1;【>> num】就可以讓num向右位移一位,檢測第二位是否是1,如此循環32次進行檢測;
? ? ? ? 缺點:無論什么數都要循環32次
方法三:
#include <stdio.h> int main() {int num = -1;int count = 0;//計數while(num){count++;num = num&(num-1);}printf("?進制中1的個數 = %d\n",count);return 0; }
????????把n的二進制序列中的最右邊的1去掉:?num = num &(num -1)
????????因為【num - 1】會讓【num】的最后一位數字1之后的數與【num-1】的不同,按位與后總會去掉n的一個1;簡而言之,num &(num -1)操作總會讓num在內存中的二進制少一個1,循環到沒有1就停止,每次循環必會少一個1,設置count++即可統計;????????舉一反三:寫一個代碼,判斷n是否是2的次方數?
????????n的2次方的特點:二進制只有一個1;
????????n &(n -1)== 0,則為2的次方數
????????練習2:二進制位置0或者置1
13的2進制序列: 00000000000000000000000000001101
將第5位置為1后:00000000000000000000000000011101
將第5位再置為0:00000000000000000000000000001101
? ? ? ? 解:
????????????????設置為1:把1的二進制進行【左移<<】后,與目標數進行【按位或 | 】操作(有1則1,同0才為0);
? ? ? ? ? ? ? ? 設置為0:把1的二進制進行【左移<<】后,與目標數進行【按位異或 ^?】操作(同0異1)
#include <stdio.h>
int main()
{int a = 13;int n = 5;//第五位改變a = a | (1<<(n - 1));printf("a = %d\n", a);a = a ^ (1<<(n - 1));printf("a = %d\n", a);return 0;
}
六、單目操作符
? ? ? ? 取反 !
? ? ? ? 自增 ++、自減?--
? ? ? ? 取地址 &、解引用?*
? ? ? ? 正 +、負?-
? ? ? ? 按位取反 ~?
? ? ? ? 計算類型大小 sizeof
? ? ? ? 強制類型轉換 (類型)
七、逗號表達式
????????逗號表達式,從左向右依次執行,整個表達式的結果是最后?個表達式的結果
? ? ? ? 注:
????????????????逗號表達式不能只看最后一個表達式,因為是從左到右依次運算,可能會涉及到最后一個表達式的變量的計算
八、下標訪問符、函數調用符
(一)下標訪問符 [ ]
????????操作數:數組名 + 下標,是雙目操作符
int arr[10];//創建數組
arr[9] = 10;//實?下標引?操作符。
[ ]的兩個操作數是arr和9。
(二)函數調用符 ( )
? ? ? ? 操作數:函數名 + 括號中的參數,所以()至少有一個操作數
?
九、結構成員訪問操作符
(一)結構體
????????C語言已經提供了內置類型,如:char、short、int、long、float、double等,但是只有這些內置類型還是不夠的,假設我想描述學生,描述?本書,這時單?的內置類型是不行的
????????描述?個學生需要名字、年齡、學號、身高、體重等;
????????描述?本書需要作者、出版社、定價等
????????C語言為了解決這個問題,增加了結構體這種自定義的數據類型,讓程序員可以自己創造適合的類型
1、概念
????????在C語言中,結構體(struct)是一種構造類型,它可以將不同的數據類型組合在一起,形成一個新的數據類型。這種新的數據類型就是結構體;
????????結構是?些值的集合,這些值稱為【成員變量】,結構的每個成員可以是不同類型的變量,如: 標量、數組、指針,甚至是其他結構體
2、結構的聲明、定義、初始化
(1)聲明
這是聲明struct 結構名
{成員;
};例如:
struct Student
{char name[20];//名字int age;//年齡char sex[5];//性別char id[20];//學號}; //分號不能丟
(2)定義?
可以在聲明時進行定義struct 結構名
{成員;}結構變量名;例如:
struct Point
{int x;int y;
}p1; 聲明類型的同時定義變量p1struct Point p2; 定義結構體變量p2
????????定義的類比:
(3)初始化
struct Student s1 = {"zhangsan", 20};//初始化
struct Student s2 = {.age=20, .name="lisi"};//指定順序初始化struct Point
{int x;int y;
}p1 = {10, 20};
????????注:
????????結構體里面有結構體,在初始化的時候就要多加一個大括號給結構體里面的那個結構體
(二)結構體成員訪問操作符
1、結構體成員的直接訪問
????????結構體成員的直接訪問是通過點操作符(.)訪問的,點操作符接受兩個操作數,如下演示:
#include <stdio.h>struct Point
{int x;int y;
}p = {1,2};int main()
{printf("x: %d y: %d\n", p.x, p.y);return 0;
}
2、結構體成員的間接訪問
#include <stdio.h>struct Point
{int x;int y;
};int main()
{struct Point p = {3, 4};struct Point *ptr = &p;ptr -> x = 10;ptr -> y = 20;printf("x = %d y = %d\n", ptr->x, ptr->y);return 0;
}
十、操作符的屬性
(一)優先級
????????優先級指的是,如果?個表達式包含多個運算符,哪個運算符應該優先執?。各種運算符的優先級是不?樣的,例如:
3 + 4 * 5;
????????上?示例中,表達式 3 + 4 * 5 ??既有加法運算符( + ),?有乘法運算符( * )。由于乘法的優先級?于加法,所以會先計算 4 * 5 ,?不是先計算 3 + 4
(二)結合性
????????如果兩個運算符優先級相同,優先級沒辦法確定先計算哪個了,這時候就看結合性了,則根據運算符是左結合,還是右結合,決定執?順序。?部分運算符是左結合(從左到右執?),少數運算符是右結合(從右到左執行),比如賦值運算符(=),如:
5 * 6 / 2;
????????上面示例中, * 和 / 的優先級相同,它們都是左結合運算符,所以從左到右執行,先計算 5 * 6 ,再計算 / 2;
????????運算符的優先級順序很多,下面是部分運算符的優先級順序(按照優先級從高到低排列),建議大概記住這些操作符的優先級就行,其他操作符在使用的時候查看下面表格就可以了
? 圓括號( () )
? ?增運算符( ++ ),?減運算符( -- )
? 單?運算符( + 和 - )
? 乘法( * ),除法( / )
? 加法( + ),減法( - )
? 關系運算符( < 、 > 等)
? 賦值運算符( = )
????????由于圓括號的優先級最高,可以使用它改變其他運算符的優先級
十一、表達式求值細節
(一)整型提升
1、概念
????????C語?中【整型算術運算】總是至少以【默認整型類型 int?】的精度來進?的;為了獲得這個精度,表達式中的【?字符char 和 短整型short?】操作數在使用之前被轉換為【普通整型 int】,這種轉換稱為整型提升,如下:
char a,b,c;
...
a = b + c;
????????b和c的值被提升為普通整型,然后再執?加法運算
????????加法運算完成之后,結果將被截斷,然后再存儲于a中(32個比特位的整型硬是要塞進char里面,就要發生截斷,截出后面8個bit位)
2、如何整型提升
????????①有符號整數提升是按照變量的數據類型的【符號位】來提升的
????????②無符號整數提升,高位補0
? ? ? ? 如下:
負數的整形提升(有符號整型):
char c1 = -1;
變量c1的?進制位(補碼)中只有8個?特位:
1111111
因為 char 為有符號的 char
所以整形提升的時候,?位補充符號位,即為1
提升之后的結果是:
11111111111111111111111111111111正數的整形提升(無符號整型):
char c2 = 1;
變量c2的?進制位(補碼)中只有8個?特位:
00000001
因為 char 為有符號的 char
所以整形提升的時候,?位補充符號位,即為0
提升之后的結果是:
00000000000000000000000000000001
(二)算術轉換
????????如果某個操作符的各個操作數屬于不同的類型,那么除非其中?個操作數的轉換為另?個操作數的類型,否則操作就無法進行,下面的層次體系稱為尋常算術轉換
long double
double
floatunsigned long int
long intunsigned int
int
從下到上轉換
????????如果某個操作數的類型在上面這個列表中排名靠后,那么首先要轉換為另外?個操作數的類型后執行運算
? ? ? ? 總結:
????????整型提升討論的是:【char 和 short】;
????????算數轉換討論的是:大于或等于【整型 int 】的其他類型
? ? ? ? 以上博客內容僅供分享,若有錯誤,請指正!