C語言-操作符與表示式
C語言入門之操作符與表示式
前言
本篇文章主要包括各種操作符的介紹與表示式求值,歡迎各位小夥伴與我一起學習。
一、操作符
分類
- 算術操作符
- 移位操作符
- 位操作符
- 賦值操作符
- 單目運算子
- 關係操作符
- 邏輯操作符
- 條件運算子
- 逗號運算子
- 下標訪問,函式呼叫和結構體員
1.算術操作符
+ 加 - 減 * 乘 / 除 % 取餘
#include <stdio.h> #include <stdlib.h> int main() { int a = 5/2; printf("%d",a); return 0; }
#include <stdio.h>
#include <stdlib.h>
int main()
{
float a = 5.0/2;
printf("%lf",a);
return 0;
}
- 除了 % 操作符之外,其他的幾個操作符可以作用於整數和浮點數。
- 對於 / 操作符,如果兩個運算元都為整數,執行整數除法。而只要有浮點數執行的就是浮點數除法。
- %操作符的兩個運算元必須為整數,返回的是整除之後的餘數。
2.移位操作符
<< 左移操作符
>> 右移操作符
左移操作符規則
#include <stdio.h> #include <stdlib.h> int main() { int a = 5; int b = a<<1; printf("%d",b); return 0; }
規則:左邊丟棄,右邊補0
警告:對於位運算子,不要移動負數位,這個是標準未定義的。
例:
int num=10;
num>> -1 ;
右移操作符規則
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 16;
// >> 右移操作符
//移動的是二進位制位
//00000000000000000000000000010000
//32個bit位
int b = a>>1;
printf("%d",b);
return 0;
}
右移操作符:
1.算術右移:
右邊丟棄,左邊補原符號位(我們見到的基本上都是算術右移)
2.邏輯右移:
右邊丟棄,左邊補0
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = -1;
//儲存到記憶體的是補碼
//1000000000000000000000000000001
//第一位是符號位,1表示負數,0表示正數
int b = a>>1;
printf("%d",b);
return 0;
}
整數的二進位制表示形式有三種(正數的反碼和補碼與原碼一樣)
原碼:直接根據數值寫出的二進位制序列
反碼:原碼的符號位不變,其他位按位取反就是反碼
補碼:反碼+1
例:
-1的原反補:
原碼:1000000 00000000 00000000 00000001
反碼:1111111 11111111 11111111 11111110
補碼:1111111 11111111 11111111 11111111
3.位操作符
按位與操作符:&
按位或操作符: |
按位異或操作符: ^
都是用補碼進行計算,如果是負數,要先找出它的補碼進行計算:a-b=a的補碼+(-b)的補碼
按位與:有一個為0,結果就為0,兩個都為1,結果才為1.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3;
int b = 5;
int c = a&b;
printf("%d",c);
return 0;
}
按位或 :有一個為1,結果就為1,兩個都為0,結果才為0.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3;
int b = 5;
int c = a|b;
printf("%d",c);
return 0;
}
按位異或 :相同為0,相異為1.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 3;
int b = 5;
int c = a^b;
printf("%d",c);
return 0;
}
不建立臨時變數(第三個變數),交換兩個數:
1.加減法
缺點:可能會溢位,不可取
a = a + b;
b = a - b;
a = a - b;
2.乘除法
缺點:可能會溢位,不可取
a = a * b;
b = a / b;
a = a / b;
3.異或法
不會溢位
a = a ^ b;
b = a ^ b;
a = a ^ b;
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 2;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a: %d \n", a);
printf("b: %d \n", b);
return 0;
}
//第一次:010^101=111
//第二次:111^101=010
//第三次:111^010=101
4.賦值操作符
賦值操作符就是你的變數已經有一個值了,但是你不滿意,你就可以使用它把一個新的值賦值給它,其實就是把右邊的值賦值到左邊,放進變數裡進行儲存。
賦值操作符是一個等號,而判斷操作符是兩個等號。
複合操作符:
+= -= ^= *= %= >>= <<= &= |= ^=
5.單目運算子
! 邏輯反操作
- 負值
+ 正值
& 取地址
sizeof 運算元的型別長度
~ 對一個數的二進位制按位取反
-- 前置,後置--
++ 前置,後置++
* 間接訪問操作符
(型別) 強制轉換型別
取地址:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 5;
int* p = &a;
*p = 10;
printf("%p\n", &a);
printf("*pa: %d\n", *pa);
printf("a: %d\n", a);
return 0;
}
sizeof 計算的是變數所佔記憶體空間的大小:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 10;
char c = 'r';
char* p = &c;
int arr[10] = { 0 };
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(c));
printf("%d\n",sizeof(p));
printf("%d\n",sizeof(arr));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
short s = 0;
int a = 10;
printf("%d\n",sizeof(s = a + 5));
//算的是s的大小,s是short型,佔兩個位元組
//sizeof裡的表示式不進行運算
printf("%d\n",s);
return 0;
}
++ 的使用:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 10;
int b = 10;
printf("%d\n",++a);
printf("%d\n",b++);
printf("%d\n",b);
return 0;
}
強制型別轉換:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = (float)3.14;
//將float型別強制轉換成int型別
printf("%d\n",a);
return 0;
}
sizeof與陣列:
#include <stdio.h>
#include <stdlib.h>
void test1(int arr[])
{
printf("%d\n",sizeof(arr));
}
void test2(char ch[])
{
printf("%d\n",sizeof(ch));
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n",sizeof(arr));
printf("%d\n",sizeof(ch));
test1(arr);
test1(ch);
return 0;
}
6.關係操作符
> , >=
< , <=
!= 不等於
== 判斷兩個數是否相等
= 賦值
7.邏輯操作符
邏輯與 &&
邏輯或 ||
&&:如果邏輯與左邊的條件為假的話,後面就不用算了
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
int b = 2;
int c = 3;
int d = 4;
int i = 0;
i = a++ && ++b && d++;
printf(" a = %d\n b = %d\n c = %d\n d = %d\n", a, b, c,d);
return 0;
}
||:如果邏輯或左邊的條件為真的話,後面就不用算了
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 0;
int b = 2;
int c = 3;
int d = 4;
int i = 0;
i = a++ || ++b || d++;
printf(" a = %d\n b = %d\n c = %d\n d = %d\n", a, b, c,d);
return 0;
}
8.條件運算子
exp1 ? exp2 : exp3
三目操作符: x > n ? 1 : 0
這裡的意思是x大於n嗎?true返回1,否則為0
9.逗號運算子
逗號表示式,就是用逗號隔開的多個表示式,從左向右依次執行,整個表示式的結果是最後一個表示式的結果。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 1;
int b = 2;
int c = (a > b,a = b + 1,a,b = a + 1);
printf("%d\n",c);
}
10.下標訪問,函式呼叫和結構成員
1. [ ]下標引用操作符,運算元:一個數組名 + 一個索引值
2. 函式呼叫操作符( ),一個函式callFunc( )
3. 結構成員訪問操作符分兩種 . 和 ->
1.下標訪問:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d\n",arr[9]);
return 0;
}
2.函式呼叫:
#include <stdio.h>
#include <stdlib.h>
int get_max(int x,int y)
{
if(x > y)
return x;
else
return y;
}
int main()
{
int a,b;
int max = 0;
scanf_s("%d%d",&a,&b);
max = get_max(a,b);
//呼叫函式的時候的()就是函式呼叫操作符
//運算元有三個,函式名get_max,引數a和b
printf("%d\n",max);
return 0;
}
3.訪問一個結構體的成員:
#include <stdio.h>
#include <stdlib.h>
struct str
{
char name[20];
char id[20];
int age;
};
int main()
{
struct str s = {"uzi", "006", 18};
printf("Name: %s\n", s.name);
printf("Id : %s\n", s.id);
printf("Age: %d\n", s.age);
return 0;
}
它本身就向記憶體申請了一部分空間,你也可以用指標來寫
#include <stdio.h>
#include <stdlib.h>
struct str
{
char name[20];
char id[20];
int age;
};
int main()
{
struct str s = {"uzi", "006", 18};
struct str* ps = &s;
printf("%s\n", (*ps).name);
//也可以這樣寫:printf("%s\n", ps->name);
return 0;
}
二、表示式求值
表示式求值的順序一部分是由操作符的優先順序和結合性決定的,
同樣,有些表示式的運算元在求值時的過程中可能需要轉換為其它型別。
隱式型別轉換
C的整型算術運算子總是至少以預設整型型別的精度來進行的。
為了獲得這個精度,表示式中的字元和短整型運算元在使用之前被轉換為普通整型,這種轉換稱為整型提升。
如何進行整體提升?
整型提升是按照資料型別的符號位來提升的。
整形提升規則:有符號數,高位補符號位 ; 無符號數,高位補0.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char a = 3;
//000000000000000000000011
//它取值時取的是它的高位:00000011 -a
char b = 127;
//000000000000000001111111
//高位:01111111 -b
char c = a + b;
//000000000000000000000011 -a
//000000000000000001111111 -b
//000000000000000010000010 -c
//a和b在這之前已經發生整型提升
printf("%d\n",c)
//高位:10000010 -c
//111111111111111110000010 -補碼
//111111111111111110000001 -反碼
//100000000000000001111110 -原碼
//-126
return 0;
}
算術轉換
如果某個操作符的各個運算元屬於不同的型別,那麼除非其中一個運算元的轉換為另一個運算元的型別,否則操作就無法進行。
下面的層次體系成為:尋常算術轉化。
long double
double
float
unsugned long int
long int
unsigned int
int
如果某個運算元的型別在上面這個列表中排名較低,那麼首先要轉換為另一個運算元的型別後執行運算,並且是低的轉換為高的。
注意:算數轉換要合理,要不然會有一些潛在的問題
操作符的屬性
複雜表示式的求值有三個影響的因素:
1.操作符的優先順序
2.操作符的結合性
3.是否控制求值順序
如果兩個操作符相鄰,先執行哪個取決於它們的優先順序,如果優先順序相同就取決於它們的結合性。
#include <stdio.h>
#include <stdlib.h>
int fun()
{
static int count = 1;
return ++count;
//2 3 4
}
int main()
{
int anwer;
anwer = fun() - fun()*fun();
printf("%d\n", anwer);
//這個程式碼是有問題的,你不知道它先呼叫的是誰
//有可能是2-3*4 又或者是4-2*3
return 0;
}
注意: 一定要保證只有唯一的一個運算順序,不然程式碼就是錯誤的。
結尾
為夢想顛簸的人有很多,不差你一個,但如果你能堅持到最後,那你就是唯一。半山腰太擠了,總得去山頂看看。