操作符詳解

Josvin發表於2020-11-05

操作符

  1. 各種操作符的介紹

操作符

分類:

  • 算術操作符
  • 移位操作符
  • 位操作符
  • 賦值操作符
  • 單目操作符
  • 關係操作符
  • 邏輯操作符
  • 條件操作符
  • 逗號表示式
  • 下標引用、函式呼叫和結構成員

算術操作符

+ -  * / %
  1. 除了 % 操作符之外,其他的幾個操作符可以作用於整數和浮點數。
  2. 對於 / 操作符如果兩個運算元都為整數,執行整數除法。而只要有浮點數執行的就是浮點數除法。
  3. % 操作符的兩個運算元必須為整數。返回的是整除之後的餘數。

移位操作符

<< 左移操作符
>> 右移操作符

左移操作符

移位規則:左邊拋棄、右邊補0
在這裡插入圖片描述

右移操作符

移位規則:首先右移運算分兩種:

  1. 邏輯移位(無符號) 左邊用0填充,右邊丟棄
  2. 算術移位(有符號) 左邊用原該值的符號位填充,右邊丟棄

在這裡插入圖片描述
警告⚠ : 對於移位運算子,不要移動負數位,這個是標準未定義的。 例如:

int num = 10;
num>>-1;//error

位操作符

位操作符有:

& //按位與
| //按位或
^ //按位異或
注:他們的運算元必須是整數。

練習一下:

#include <stdio.h>
int main()
{
int num1 = 1;
int num2 = 2;
num1 & num2;
num1 | num2;
num1 ^ num2;
return 0;
}

一道變態的面試題

不能建立臨時變數(第三個變數),實現兩個數的交換。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;
a = a^b;// 異或相同為0 不同為1
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;

}
//思考這樣的實現方式有沒有問題?
//方法2:
#include <stdio.h>
int main()
{
int num = -1;
int i = 0;
int count = 0;//計數
for(i=0; i<32; i++)
{
if( ((num>>i)&1) == 1 )
count++;
}
printf("二進位制中1的個數 = %d\n",count);
return 0;
}
//思考還能不能更加優化,這裡必須迴圈32次的。
//方法3:
#include <stdio.h>
int main()
{
int num = -1;
int i = 0;
int count = 0;//計數
while(num)
{
count++;
num = num&(num-1);// 運算一次就會少一個1,迴圈了多少次那麼就會有多少個1
}
printf("二進位制中1的個數 = %d\n",count);
return 0;
}
//這種方式是不是很好?達到了優化的效果,但是難以想到。

賦值操作符

賦值操作符是一個很棒的操作符,他可以讓你得到一個你之前不滿意的值。也就是你可以給自己重新賦值。

int weight = 120;//體重
weight = 89;//不滿意就賦值
double salary = 10000.0;
salary = 20000.0;//使用賦值操作符賦值。
賦值操作符可以連續使用,比如:
int a = 10;
int x = 0;
int y = 20;
a = x = y+1;//連續賦值
這樣的程式碼感覺怎麼樣?
那同樣的語義,你看看:
x = y+1;
a = x;
這樣的寫法是不是更加清晰爽朗而且易於除錯。

複合賦值符

+=
-=
*=
/=
%=

=
<<=
&=
|=
^=

這些運算子都可以寫成複合的效果。 比如:

int x = 10;
x = x+10;
x += 10;//複合賦值
//其他運算子一樣的道理。這樣寫更加簡潔。

單目操作符

!      邏輯反操作
-      負值
+      正值
&      取地址
sizeof    運算元的型別長度(以位元組為單位)
~      對一個數的二進位制按位取反
--      前置、後置--
++      前置、後置++
*      間接訪問操作符(解引用操作符)
(型別)    強制型別轉換

注意:
強轉並不改變目標資料的二進位制序列,只改變看待他的方式(哪種型別)
轉化本質是對資料的二進位制序列進行改變。

演示程式碼:

#include <stdio.h>
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;
}

關於sizeof其實我們之前已經見過了,可以求變數(型別)所佔空間的大小。
sizeof和陣列

#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)兩個地方分別輸出多少?  // 40  43)、(4)兩個地方分別輸出多少?  // 10  4

注意;傳的指標型別都是4位元組。

//++和--運算子
//前置++和--
//前置++和--:
#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;
}

關係操作符

注意:不能用來判斷字串關係

>
>=
<
<=
!=  用於測試“不相等”
==    用於測試“相等”

這些關係運算子比較簡單,沒什麼可講的,但是我們要注意一些運算子使用時候的陷阱。
警告: 在程式設計的過程中== 和=不小心寫錯,導致的錯誤。

邏輯操作符

&&   邏輯與
||      邏輯或

區分邏輯與按位與 區分邏輯或按位或

1&2----->0
1&&2---->1
1|2----->3
1||2---->1

360筆試題

#include <stdio.h>
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則可以直接返回,後邊的就會發生短路。
注意當邏輯與的時候,有0則可以直接返回,後邊的就會發生短路。

條件操作符

exp1 ? exp2 : exp3

練習:

1.
if (a > 5)
    b = 3;
else
    b = -3;
轉換成條件表示式,是什麼樣?
2.使用條件表示式實現找兩個數中較大值。

比較簡單我就不寫了。

逗號表示式

exp1, exp2, exp3, …expN

逗號表示式,就是用逗號隔開的多個表示式。 逗號表示式,從左向右依次執行。整個表示式的結果是最後一個表示式的結果。

//程式碼1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗號表示式
c是多少?
//程式碼2
if (a =b + 1, c=a / 2, d > 0)
//程式碼3
a = get_val();
count_val(a);
while (a > 0)
{
    //業務處理
    a = get_val();
    count_val(a);
}
如果使用逗號表示式,改寫:
while (a = get_val(), count_val(a), a>0)
{
    //業務處理
}
int arr[10];//建立陣列
arr[9] = 10;//實用下標引用操作符。
[ ]的兩個運算元是arr和9

下標引用、函式呼叫和結構成員

1.[ ] 下標引用操作符
運算元:一個陣列名 + 一個索引值

int arr[10];//建立陣列
arr[9] = 10;//實用下標引用操作符。
[ ]的兩個運算元是arr和9

2.( ) 函式呼叫操作符 接受一個或者多個運算元:第一個運算元是函式名,剩餘的運算元就是傳遞給函式的引數。

#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1();       //實用()作為函式呼叫操作符。
test2("hello bit.");//實用()作為函式呼叫操作符。
return 0;
}

3.訪問一個結構的成員
. 結構體.成員名
-> 結構體指標->成員名

#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;//結構成員訪問
}
int main()
{
struct Stu stu;
struct Stu* pStu = &stu;//結構成員訪問
stu.age = 20;//結構成員訪問
set_age1(stu);
pStu->age = 20;//結構成員訪問
set_age2(pStu);
return 0;
}

相關文章