●🧑個人主頁:你帥你先說.
●📃如果文章有幫助,歡迎點贊👍關注💡收藏💖
●📖既選擇了遠方,便只顧風雨兼程,
●🤟歡迎大家有問題隨時私信我!
●🧐著作權:本文由[你帥你先說.]原創,CSDN首發,侵權必究,
目錄
1.算術運算子
2.移位運算子
3.位運算子
3.1 &(按位與)
3.2 |(按位或)
3.3 ^(按位異或)
4.賦值運算子
5.復合賦值符
6.單目運算子
6.1!(邏輯反操作)
6.2 sizeof
6.3 ~(按位取反)
6.4 &取地址
6.5 *解參考運算子
6.6 ++、-- 運算子
7.關系運算子
8.邏輯運算子
9.條件運算子
10.逗號運算式
11.下標參考、函式呼叫和結構成員
11.1[ ] 下標參考運算子
11.2( ) 函式呼叫運算子
12.結構成員
13.運算式求值
13.1隱式型別轉換
13.2算術轉換
13.3運算子的屬性
1.算術運算子
+ - * / %
int ret = 9/2;
double ret = 9/2;
大家可能會認為9/2算出來是4是因為int整型,實際上不是,當你以double型別列印時結果是4.0,所以說這是‘/’自身的特點,并不是int型別造成的,
那要怎么算出4.5呢?
上面第二點提到了,只要有浮點數就執行浮點數除法,所以可以改成9.0/2或者9/2.0就能算出4.5了,
2.移位運算子
<< 左移運算子>> 右移運算子
移位運算子,移動的是二進制位
對于整數的二進制有3中表示形式:原碼、反碼、補碼
正整數 - 原碼、反碼、補碼相同
負整數
原碼 - 直接按照數字的正負寫出的二進制序列
反碼 - 原碼的符號位不變,其他位按位取反得到的
補碼 - 反碼+1
二進制的第一位為符號位,負數為1,正數為0,
整數在記憶體中存盤的是二進制的補碼
那移位運算子是怎么對二進制進行移位的呢?
int a = 5;
int b = a << 1;
以32bit系統為例
算出來結果是10
注意:此時a的值還是5,b的值是10,移位運算子并不對自身進行改變,
剛剛上面是以左移運算子為例,實際上右移運算子遵循的規則和左移略有不同,
首先右移運算分兩種:1. 邏輯移位左邊用0填充,右邊丟棄2. 算術移位左邊用原符號位填充,右邊丟棄
大部分編譯器采用的是算術移位,
int a = -1;
int b = a >> 1;
圖解

因為-1的原符號位是1,所以補1,
3.位運算子
& 按位與
| 按位或
^ 按位異或注:他們的運算元必須是整數,
3.1 &(按位與)
int a=3 b=5;
c=a&b;
a的二進制 00000000000000000000000000000011
b的二進制 00000000000000000000000000000101
結果為 00000000000000000000000000000001
即只要有0即為0,其余不變(1向左移位按位與這個數可以找二進制里有幾個1)
3.2 |(按位或)
a的二進制 00000000000000000000000000000011
b的二進制 00000000000000000000000000000101
結果為 00000000000000000000000000000111
即只要有1即為1,其余不變
3.3 ^(按位異或)
a的二進制 00000000000000000000000000000011
b的二進制 00000000000000000000000000000101
結果為 00000000000000000000000000000110
相同為0,相異為1
異或是支持交換律的!
在這里有一道非常經典的變態面試題
不能創建臨時變數(第三個變數),實作兩個數的交換
int a = 3,b = 5;
a = a + b;
b = a - b;
a = a - b;
但這種方法有個局限,因為整型變數有上限,如果資料過大可能會導致溢位,
法二:
int a = 3;
int b = 5;
a = a^b;
b = a^b;
a = a^b;
圖解

這個解法只是就題解題,平時我們在寫代碼時避免寫出這種可讀性差的代碼,
4.賦值運算子
賦值運算子是一個很棒的運算子,他可以讓你得到一個你之前不滿意的值,也就是你可以給自己重新賦值,
int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//連續賦值
這個運算式是從右向左依次賦值的,但平時我們不建議這種寫法,
最好寫成以下這樣
x = y + 1;
a = x;
5.復合賦值符
+= 例如a+=5就相當于a = a +5,下面的以此類推,
-=
*=
/=
%=
>>=
<<=
&=
|=
^=
6.單目運算子
! 邏輯反操作- 負值+ 正值& 取地址sizeof 運算元的型別長度(以位元組為單位)~ 對一個數的二進制按位取反-- 前置、后置 --++ 前置、后置 ++* 間接訪問運算子 ( 解參考運算子 )( 型別 ) 強制型別轉換
6.1!(邏輯反操作)
C語言是如何表示真偽的?
0位假,非0為真,C語言規定真所對應的值為1,所以 0為假 !0 為真,
6.2sizeof
這邊強調一點大家容易誤解的,sizeof是運算子不是函式!
int a = 5;
short s = 10;
printf("%d\n", sizeof(s = a + 2));//結果為2
printf("%d\n", s); //結果為10

sizeof()最終算的型別是運算式最終的型別,當把int型別賦給short int 型別時會發生截斷,
6.3~(按位取反)
00000000000000000000000000001111
11111111111111111111111111111110000
即0和1互換
6.4&取地址
int a = 10;
int * p = &a;
取地址時取出的是4個位元組中的第一個位元組,且是低地址,
6.5*解參考運算子
int a = 10;
int * p = &a;
*p = 20; //解參考運算子
*p表示通過p找到a的地址從而改變a的內容,
int b = *p;//右值
*p = 20;//左值
當*p在等號左右兩邊所表達的意義不同,
左值代表空間,右值代表空間的內容,
6.6 ++、-- 運算子
這里以++為例
前置++
int a = 10;
int b = a++;
//最終結果為 a為11 b為10,后置++,先賦值,后++
int a = 10;
int b = ++a;
//最終結果為 a為11 b為11,前置++,先++,后賦值
7.關系運算子
>>=<<=!= 用于測驗 “ 不相等 ”== 用于測驗 “ 相等 ”
8.邏輯運算子
&& 邏輯與|| 邏輯或
#include <stdio.h>
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0;
}
此題輸出結果為1234,首先,a++,是先使用后++,a是0,0是假,所以不管后面的運算式是什么,最終結果都是假,后面的運算式沒有參與運算,故結果為1234,
9.條件運算子
exp1 ? exp2 : exp3
b = a > 5 ? 3 : -3;
這段代碼等價于下面這段代碼
if (a > 5)
b = 3;
else
b = -3;
10.逗號運算式
exp1 , exp2 , exp3.....expn
從左向右依次計算,整個運算式的結果是最后一個運算式的結果,
int a=3,b=5,c=6;
int d=(a=a-2,b=a+c,c=a-b);//逗號運算式的結果即為c=a-b的結果
printf("%d",d);//輸出結果為-6
11.下標參考、函式呼叫和結構成員
11.1[ ] 下標參考運算子
int arr[10];//創建陣列
arr[9] = 10;//實用下標參考運算子,
//[ ]的兩個運算元是arr和9,
所以arr[10]也可以寫成10[arr],因為arr和10就是兩個運算元,可以交換順序,只是平時我們習慣寫arr[10],
11.2( ) 函式呼叫運算子
#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1(); //使用()作為函式呼叫運算子,
test2("hello world.");//使用()作為函式呼叫運算子,
return 0;
}
12.結構成員
. 結構體.成員名
-> 結構體指標->成員名
#include <string.h>
struct Book
{
char name[20];
float price;
char id[10];
};
void print1(struct Book b)
{
printf("書名: %s\n", b.name);
printf("價格: %f\n", b.price);
printf("書號: %s\n", b.id);
}
void print2(struct Book* pb)
{
printf("書名: %s\n", pb->name);
printf("價格: %f\n", pb->price);
printf("書號: %s\n", pb->id);
}
int main()
{
struct Book b = {"C語言程式設計", 55.5f, "C20190201"};
print2(&b);
return 0;
}
在這里強調一點,如果要對結構體里的內容進行改變,不可直接改,要用strcpy函式進行更改,例如strcpy(b.name, "資料結構"),因為b.name中name是陣列名,是首元素的地址,如果直接對b.name進行更改相當于是對地址進行更改,而你要改的是內容,這種做法肯定是錯的,
13.運算式求值
運算式求值的順序一部分是由運算子的優先級和結合性決定,
同樣,有些運算式的運算元在求值的程序中可能需要轉換為其他型別
13.1隱式型別轉換
C 的整型算術運算總是至少以預設整型型別的精度來進行的,為了獲得這個精度,運算式中的字符和短整型運算元在使用之前被轉換為普通整型,這種轉換稱為 整型 提升 ,
看完這段話,你一定是這樣的

舉個栗子![]()
int main()
{ char a = 3;//a是1byte - 8bit
//發生整型提升的程序
//00000000000000000000000000000011
//00000011 - a 發生截斷
char b = 127;//b是1byte - 8bit
//00000000000000000000000001111111
//01111111 - b
//a和b都是char型別,自身大小的都是1byte,所以這里計算的時候要進行整型提升
//整形提升是按照變數的資料型別的符號位來提升的,正數補0,負數補1,無符號數補0
//例如a是00000011最高位為0,所以前面補0若a是-1則11111111最高位是1,前面補1
//00000000000000000000000000000011 a
//00000000000000000000000001111111 b
//00000000000000000000000010000010 a+b
//
char c = a + b;
//10000010 - c 發生截斷
printf("%d\n",c);
//11111111111111111111111110000010 最高位為1,前面補1,記憶體中存的是補碼
//11111111111111111111111110000001 反碼 補碼-1就是反碼
//10000000000000000000000001111110 原碼 反碼按位取反就是原碼
//-126
return 0;
}
整型提升的具體例子
int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if(a==0xb6)
printf("a");
if(b==0xb600)
printf("b");
if(c==0xb6000000)
printf("c");
return 0;
}
列印結果為c,因為c是int不用整型提升,而char和short都需要整型提升,
int main()
{
char c = 1;
printf("%u\n", sizeof(c));//1byte
printf("%u\n", sizeof(+c));//4byte
printf("%u\n", sizeof(-c));//4byte
return 0;
}
第一個因為c是char型別所以是1個位元組,而第二第三個因為+-號所以c參與了運算,要進行整型提升,所以是4個位元組,
13.2算術轉換
long doubledoublefloatunsigned long intlong intunsigned intint
轉換優先級自下而上,例如
float a = 3.7
double b = 3.14
//則a*b結果的型別是double
13.3運算子的屬性
那什么是結合性呢?
舉個栗子![]()
比如a+b+c到底是先a+b 再加c還是先b+c再加a呢?表中也寫了方向是從左向右,所以是先a+b再加c,
優先級的作用物件是相鄰運算子,
a*b+c*d+e*f
這個式子的計算路徑有兩種
一是:
第二種計算路徑說明了優先級作用的物件是相鄰運算子,
這段代碼實際上是問題代碼,因為計算路徑不唯一,平時寫程式時一定要確保計算路徑的唯一性,
看完這些,此刻的你


這樣的文章你還不趕緊 點贊收藏+關注作者!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/294272.html
標籤:其他
上一篇:C++ 吃透動態規劃演算法
下一篇:資料型別的存盤
