一篇文章帶你了解C語言操作符
操作符和表達式
我們在初始C語言已經(jīng)大致了解了操作符,我們今天一起詳細解剖操作符。
操作符
C語言操作符很多,但大致進行分類后,有以下幾種操作符
//算數(shù)操作符 + - * / % //移位操作符 << >> //位操作符 & | //賦值操作符 = += -= *= /= ... //單目操作符 sizeof() ! ++ -- & * //關(guān)系操作符 > >= < <= == //邏輯操作符 && || //條件操作符 ?: //逗號表達式 , //其他操作符 [] () -> . ...
算數(shù)操作符
算數(shù)操作符再常見不過,
加減乘除,取余。
+ - * /操作符和我們數(shù)學(xué)上的一樣。
值得注意的是
/
int c=10/3; c=10.0/3; c=10/3.0; //c結(jié)果為3 (double)c=10.0/3; //能計算出小數(shù)值
C語言中,/需要至少一個操作數(shù)為浮點數(shù),才能使結(jié)果為浮點數(shù),并且記得存在浮點數(shù)中。
%求余(取模)操作符
只能計算兩個整型之間的結(jié)果,結(jié)果也為整型。

移位操作符
這里說的移位,指的是移動二進制位。
有左移,右移操作符。
<<左移操作符
向左移動二進制位

可以看到二進制左移后,a<<1是a的2倍,所以我們可以知道,左移一位,擴大2倍。
左移n位擴大2^n倍。
>>右移操作符
可想而知,右移操作符,也與左移效果類似,二進制位向右移動一位。
右邊的二進制丟棄,右邊的二進制位,并不是添像左移操作符一樣添零,需要分情況討論。
移位又分為算數(shù)移位和邏輯移位。
算數(shù)移位就是右移時,左邊添加那一位是需要看二進制的符號位,添加。添加的哪一位和符號位相同。
邏輯移位就是不管左移還是右移操作,添加哪一位都是添0。
但我們需要移動一個負數(shù)時,顯然邏輯移位會改變原數(shù)值得正負。
所以在一般的編譯器下都采用算數(shù)移位。

可以看到右移操作原來的值縮小了2^n倍。
注意:左移和右移都要考慮移位后是否會溢出。
移位操作是針對移動正數(shù)位,
a>>-1這樣移位錯誤,C語言未定義。
位操作符
位操作,有&(按位與) , |(按位或),^(按位異或)~(按位取反)。
位操作符顧名思義,是針對二進制位的操作,有兩個操作數(shù)進行,二進制位進行操作運算。
這里我們的二進制位都是指的補碼,因為一個數(shù)以補碼的形式存放在內(nèi)存中。
// 00000000 00000000 00000000 00100010 // 00000000 00000000 00000000 11010110 // & 00000000 00000000 00000000 00000010 // | 00000000 00000000 00000000 11110110 // ^ 00000000 00000000 00000000 11110100
| 位操作符 | 作用 |
|---|---|
& |
兩操作數(shù)二進制位都為真(1)結(jié)果為真(1)否者為假(0) |
| |
兩操作數(shù)二進制位為假(0)結(jié)果為假(0)否者為真(1) |
^ |
一真(1)一假(0)結(jié)果為真(1),否者為假(0) |
~ |
二進制位按位取反,1變0,0變1 |
位操作符的應(yīng)用
//嘗試寫一下這個代碼
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)建新的變量,實現(xiàn)兩個變量的交換。
//方法一
#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ì)解題,寫出優(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
}
求一個整數(shù)存儲在內(nèi)存中二進制1的個數(shù)
//方法一
#include<stdio.h>
int main()
{
int n=10;
int count=0;
while(n)
{
if(n%2==1)
{
count++;
}
n>>=1;
}
printf("輸入二進制位1的個數(shù):%d",count);
}

思考上面的代碼是否存在問題
當(dāng)n為負數(shù)時?

可以看到程序?qū)恢彼姥h(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;
}

每次都要進行32次循環(huán),我們是否可以再次優(yōu)化一下!
//方法三
#include <stdio.h>
int main()
{
int num = -1; // 10000000 00000000 00000000 00000001
//補碼 11111111 11111111 11111111 11111111
int i = 0;
int count = 0;//計數(shù)
while(num)
{
count++;
num = num&(num-1);//丟棄最后一位1
}
printf("二進制中1的個數(shù) = %d\n",count);
return 0;
}

上面這個代碼是不是很神奇,一般人想不到,這就是代碼的魅力!
賦值操作符
賦值操作符,我們再熟悉不過了。
我們可以通過賦值操作符,將一個變量改變成你想要的值!
#include<stdio.h>
int main()
{
int weight=180;
weight=125; //不滿意可以改變
//連續(xù)賦值
int a=13,b=0,c=0;
a=b=c=6;
//連續(xù)賦值操作缺點不易調(diào)試
}
復(fù)合賦值操作符
+= -= *= /= %= …
可以看到很多復(fù)合賦值操作符
a+=2; ===> a=a+2;
a*3; ===> a=a*3;
//其他運算符一個道理
....
這邊是復(fù)合賦值操作符,使用起來很簡單,也很方便!
單目操作符
//單目操作符就是只有一個操作數(shù)的操作符! + - ! sizeof() ++ -- ~ * (類型)
+ -
這里的+ -都是單目操作符,并不是算數(shù)操作符中的+-!
a=-5; //-5這里的-指的是單目操作符!
b=+5; //+5 +可以省略!
!
邏輯反操作符
while(a!=0) //這里就是!邏輯反操作符
{
count++; //a不為0count++;
}
while(!a)
{
count++; //a為0count++;
}
sizeof
是否感到很詫異,sizeof居然是操作符!
sizeof是比較特殊的一個操作符,并不是函數(shù)!
我們知道sizeof可以計算一個變量和類型的所占空間內(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); //這樣寫行不行?
printf("%d\n", sizeof int);//這樣寫行不行?
return 0;
}

可以看到當(dāng)sizeof計算一個類型時,不添加括號,就會報錯,然而計算一個變量的大小時卻可以省略括號!
總結(jié):sizeof計算類型所占內(nèi)存大小時,括號不可省略。sizeof(類型),計算變量所占內(nèi)存大小時,sizeof(變量),sizeof變量
將錯誤更改一下,看一下運行結(jié)果!

sizeof和數(shù)組
我們知道sizeof可以計算變量的空間大小,所以我們經(jīng)常通過sizeof計算一個數(shù)組的元素個數(shù)!
公式:sizeof(數(shù)組)/sizeof(數(shù)組的一個元素)
#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;
}
問:
(1)、(2)兩個地方分別輸出多少?
(3)、(4)兩個地方分別輸出多少?
我們先通過自己計算一下!
計算結(jié)果!
(1)40 (2) 40 (3)10 (4) 10
而運行結(jié)果!

可以看到,運行結(jié)果并不是那樣!
我們在思考一下這個結(jié)果,為啥結(jié)果會是4?
我們明明是將數(shù)組,直接傳參過去 ,而通過sizeof計算的內(nèi)存大小卻不是,難道我們只傳參了一個地址過去?

我們調(diào)試一下,發(fā)現(xiàn)就是假設(shè)的這樣,數(shù)組傳參并沒有將整個數(shù)組傳參過去,而是傳參了一個指針!
而我們在x86也就是32位平臺下,指針所占內(nèi)存空間大小為4個字節(jié)。
++ --
//前置++和--:
#include <stdio.h>
int main()
{
int a = 10;
int x = ++a;
//先對a進行自增,然后對使用a,也就是表達式的值是a自增之后的值。x為11。
int y = --a;
//先對a進行自減,然后對使用a,也就是表達式的值是a自減之后的值。y為10;
return 0;
}
//后置++和--
#include <stdio.h>
int main()
{
int a = 10;
int x = a++;
//先對a先使用,再增加,這樣x的值是10;之后a變成11;
int y = a--;
//先對a先使用,再自減,這樣y的值是11;之后a變成10;
return 0;
}
總結(jié): 前置++,--先進行自加操作,再使用!
后置++,--先使用再進行自加操作!
關(guān)系操作符
> >= < <= == (判斷是否等于) !=(判斷不等于)
這些這是基本的關(guān)系操作符!
我們已經(jīng)很常見了,我們看一下關(guān)系操作符的運行結(jié)果!
可以看到,當(dāng)判斷結(jié)果為真是,vs用1代表真,用0代表假。

注意:我們在測試,結(jié)果是否相等時,用==而不是賦值操作符=。
邏輯操作符
邏輯操作符,有邏輯與&&,邏輯或||
當(dāng)我們要測試兩個表達式結(jié)果時,如果要同時滿足,使用邏輯與&&只需滿足其中一個表達式結(jié)果時使用邏輯或||
我們要區(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;
}

位操作符和邏輯操作符截然不同,一個是對整數(shù)的二進制進行操作,另一個是對表達式的結(jié)果進行判斷!
&& 只有當(dāng)兩個表達式結(jié)果同時為真,結(jié)果才為真!
|| 只有當(dāng)兩個表達式結(jié)果同時為假,結(jié)果才為假!
邏輯表達式的特性!
#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;
}

我們可以看到,邏輯或||第二個表達式,并沒有執(zhí)行。
這是為什么呢!
總結(jié): 邏輯與&&當(dāng)執(zhí)行到表達式結(jié)果為假,便停止執(zhí)行,后面的表達式!
邏輯或||當(dāng)執(zhí)行到表達式結(jié)果為真,便停止執(zhí)行后面的表達式!
這就是我們常說的邏輯短路特點!
條件操作符
exp1 ? exp2 : exp3
條件操作符通常由3個表達式構(gòu)成!又叫(三目操作符)!
如果exp1表達式結(jié)果為真,執(zhí)行exp2,否者執(zhí)行exp3
可以看到與我們的判斷語句if類似!
#include<stdio.h>
int main()
{
int a=5,b=3,max=0;
//if判斷語句求最大值
if(a>b)
{
max=a;
}
else
{
max=b;
}
//條件表達式
a>b?max=a:max=b;
return 0;
}
可以看到條件表達式的優(yōu)點,可以大大的簡化代碼!
逗號表達式
exp1,exp2,exp3...expN
表達式之間用,分隔開,這就是逗號表達式。
表達式特點
#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;
}

可以看到表達式i=(a++,b++,c);結(jié)果i=5也就是最后一個表達式c的值。
逗號表達式運算特點:
表達式從左往右依次計算,最后一個表達式的值,便是整個逗號表達式結(jié)果的值!
其他操作符
[]下標引用操作符 ()函數(shù)調(diào)用操作符 . ->結(jié)構(gòu)成員訪問操作符
[]下標引用操作符
操作數(shù):一個數(shù)組名+一個索引值
int arr[10];//創(chuàng)建數(shù)組
arr[9] = 10;//實用下標引用操作符。
// [ ]的兩個操作數(shù)是arr和9。
既然是兩個操作數(shù),那么兩個操作數(shù)可以交換位置嗎?

可以看到arr[9]等價9[arr]
但是我們并不介意用9[arr]
()函數(shù)調(diào)用操作符
( ) 函數(shù)調(diào)用操作符
接受一個或者多個操作數(shù):第一個操作數(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ù)調(diào)用操作符。
test2("hello bit.");//實用()作為函數(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)成員訪問
}
int main()
{
struct Stu stu;
struct Stu* pStu = &stu;//結(jié)構(gòu)成員訪問
stu.age = 20;//結(jié)構(gòu)成員訪問
set_age1(stu);
pStu->age = 20;//結(jié)構(gòu)成員訪問
set_age2(pStu);
return 0;
}
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
openCV中meanshift算法查找目標的實現(xiàn)
本文主要介紹了openCV中meanshift算法查找目標的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11

