当前位置:网站首页>C語言-入門-基礎-語法-[運算符,類型轉換](六)
C語言-入門-基礎-語法-[運算符,類型轉換](六)
2022-07-04 08:48:00 【胡安民】
運算符基本概念
和數學中的運算符一樣, C語言中的運算符是告訴程序執行特定算術或邏輯操作的符號
什麼是錶達式: 錶達式就是利用運算符鏈接在一起的有意義,有結果的語句; 例如: a + b; 就是一個算數錶達式, 它的意義是將兩個數相加, 兩個數相加的結果就是錶達式的結果 注意: 錶達式一定要有結果
運算符分類
按照功能劃分:
- 算術運算符
- 賦值運算符
- 關系運算符
- 邏輯運算符
- 比特運算符
按照參與運算的操作數個數劃分:
- 單目運算 , 只有一個操作數 如 : i++;
- 雙目運算 , 有兩個操作數 如 : a + b;
- 三目運算 , C語言中唯一的一個,也稱為問號錶達式 如: a>b ? 1 : 0;
運算符的優先級和結合性
早在小學的數學課本中,我們就學習過"從左往右,先乘除後加减,有括號的先算括號裏面的", 這句話就蘊含了優先級和結合性的問題
C語言中,運算符的運算優先級共分為15 級。1 級最高,15 級最低
- 在C語言錶達式中,不同優先級的運算符, 運算次序按照由高到低執行
- 在C語言錶達式中,相同優先級的運算符, 運算次序按照結合性規定的方向執行
算數運算符
注意事項
- 如果參與運算的兩個操作數皆為整數, 那麼結果也為整數
- 如果參與運算的兩個操作數其中一個是浮點數, 那麼結果一定是浮點數
- 求餘運算符, 本質上就是數學的商和餘,中的餘數
- 求餘運算符, 參與運算的兩個操作數必須都是整數, 不能包含浮點數
- 求餘運算符, 被除數小於除數, 那麼結果就是被除數
- 求餘運算符, 運算結果的正負性取决於被除數,跟除數無關, 被除數是正數結果就是正數,被除數
- 是負數結果就是負數
- 求餘運算符, 被除數為0, 結果為0
- 求餘運算符, 除數為0, 沒有意義(不要這樣寫)
賦值運算符
簡單賦值運算符
複合賦值運算符
結合性和優先級
自增自减運算符
在程序設計中,經常遇到“i=i+1”和“i=i-1”這兩種極為常用的操作。C語言為這種操作提供了兩個更為簡潔的運算符,即++
和--
如果出現在一個錶達式中, 那麼符號寫在前面和後面就會有所區別
前綴錶達式:
++x, --x;
其中x錶示變量名,先完成變量的自增自减1運算,再用x的值作為錶達式的
值;即“先變後用”,也就是變量的值先變,再用變量的值參與運算後綴錶達式:
x++, x--;
先用x的當前值作為錶達式的值,再進行自增自减1運算。即“先用後變”,也
就是先用變量的值參與運算,變量的值再進行自增自减變化
自增:
如果只有單個變量, 無論++寫在前面還是後面都會對變量做+1操作
如果自增參與運算
自减
注意:
- 自增、自减運算只能用於單個變量,只要是標准類型的變量,不管是整型、實型,還是字符型變量
等,但不能用於錶達式或常量 ,錯誤用法:++(a+b);
- 開發中盡量讓
++ --
單獨出現, 盡量不要和其它運算符混合在一起
請用如下代碼替代
C語言標准沒有明確的規定, 同一個錶達式中同一個變量自增或自减後如何運算 , 不同編譯器得到結果也不同, 在企業開發中千萬不要這樣寫
sizeof運算符
sizeof可以用來計算一個變量或常量、數據類型所占的內存字節數
標准格式: sizeof(常量 or 變量);
sizeof()和+=、*=
一樣是一個複合運算符, 由sizeof和()兩個部分組成, 但是代錶的是一個整體
所以sizeof不是一個函數, 是一個運算符, 該運算符的優先級是2
sizeof的幾種形式:
// sizeof( 變量\常量 );
sizeof(10);
char c = 'a';
sizeof(c);
//sizeof 變量\常量;
sizeof 10;
char c = 'a';
sizeof c;
// sizeof( 數據類型);
sizeof(float); //如果是數據類型不能省略括號
逗號運算符
- 在C語言中逗號“,”也是一種運算符,稱為逗號運算符。 其功能是把多個錶達式連接起來組成一個錶達式,稱為逗號錶達式
- 逗號運算符會從左至右依次取出每個錶達式的值, 最後整個逗號錶達式的值等於最後一個錶達式的
值 - 格式:
錶達式1,錶達式2,… …,錶達式n;
#include <stdio.h>
int main(){
int a=2,b=4,x,y;
y=(x=a+b,b+x); //在逗號錶達式中,最後一個運算才是最終的值,然後賦值給y
printf("y=%d, x=%d \n",y,x);// y=10, x=6
return 0;
}
關系運算符
默認情况下,我們在程序中寫的每一句正確代碼都會被執行。但很多時候,我們想在某個條件成立的情况下才執行某一段代碼, 這種情况的話可以使用條件語句來完成,但是學習條件語句之前,我們先來看一些更基礎的知識:
如何判斷一個條件是否成立, C語言中的真假性 , 在C語言中,條件成立稱為“真”,條件不成立稱為“假”,因此,判斷條件是否成立,就是判斷條件的“真假”
怎麼判斷真假呢?C語言規定,任何數值都有真假性,任何非0值都為“真”,只有0才為“假”。也就是說,108、-18、4.5、-10.5等都是“真”
,0則是“假
關系運算符的運算結果只有2種:如果條件成立,結果就為1,也就是“真”;
如果條件不成立,結果 就為0,也就是“假
優先級和結合性
注意: 無論是float還是double都有精度問題, 所以一定要避免利用==判斷浮點數是否相等
邏輯運算符
優先級 | 名稱 | 符號 | 說明 |
---|---|---|---|
2 | 邏輯非運算符 | ! | 單目運算符,具有右結合性 |
11 | 邏輯與運算符 | && | 雙目運算符,具有左結合性 |
12 | 邏輯或運算符 | || | 雙目運算符,具有左結合性 |
邏輯非
格式: ! 條件A; (真變假,假變真)
邏輯與
格式: 條件A && 條件B;
運算結果:一假則假 ,也就是都為真那麼才是真
運算過程:
- 總是先判斷"條件A"是否成立,如果"條件A"成立,接著再判斷"條件B"是否成立, 如果"條件B"也成立,結果就為1,即“真”
- 如果"條件A"成立,"條件B"不成立,結果就為0,即“假”
- 如果"條件A"不成立,不會再去判斷"條件B"是否成立, 因為邏輯與只要一個不為真結果都不為真
使用注意: 條件A"為假, "條件B"不會被執行
邏輯或
格式: 條件A || 條件B;
運算結果:一真則真
運算過程:
- 先判斷"條件A"是否成立
- 如果"條件A"不成立,接著再判斷"條件B"是否成立, 如果"條件B"成立,結果就為1,即“真”
- 如果"條件A"不成立,"條件B"也不成立成立, 結果就為0,即“假”
- 如果"條件A"成立, 不會再去判斷"條件B"是否成立, 因為邏輯或只要一個為真結果都為真
使用注意: "條件A"為真, "條件B"不會被執行
三目運算符
三目運算符,它需要3個數據或錶達式構成條件錶達式
格式1: 錶達式1?(結果A):(結果B)
格式2: 錶達式1?錶達式2:錶達式3
示例: 考試及格 ? 及格 : 不及格;
求值規則: 如果"錶達式1"為真,三目運算符的運算結果為(結果A),否則為(結果B)
我們還可以進行複雜點的 int res = a>b?a:(c>d?c:d);
類型轉換
數據類型轉換就是將數據(變量、數值、錶達式的結果等)從一種類型轉換為另一種類型。
自動類型轉換
自動類型轉換就是編譯器默默地、隱式地、偷偷地進行的數據類型轉換,這種轉換不需要程序員幹預,會自動發生。將一種類型的數據賦值給另外一種類型的變量時就會發生自動類型轉換,例如:
//100 是 int 類型的數據,需要先轉換為 float 類型才能賦值給變量 f。
float f = 100;
//再如:f 是 float 類型的數據,需要先轉換為 int 類型才能賦值給變量 n。
int n = f;
在賦值運算中,賦值號兩邊的數據類型不同時,需要把右邊錶達式的類型轉換為左邊變量的類型,這可能會導致數據失真,或者精度降低;所以說,自動類型轉換並不一定是安全的。對於不安全的類型轉換,編譯器一般會給出警告。
在不同類型的混合運算中,編譯器也會自動地轉換數據類型,將參與運算的所有數據先轉換為同一種類型,然後再進行計算。轉換的規則如下:
- 轉換按數據長度增加的方向進行,以保證數值不失真,或者精度不降低。例如,int 和 long 參與運算時,先把 int 類型的數據轉成 long 類型後再進行運算。
- 所有的浮點運算都是以雙精度進行的,即使運算中只有 float 類型,也要先轉換為 double 類型,才能進行運算。
- char 和 short 參與運算時,必須先轉換成 int 類型。
下圖對這種轉換規則進行了更加形象地描述:
unsigned 也即 unsigned int,此時可以省略 int,只寫 unsigned。
自動類型轉換示例:
#include<stdio.h>
int main(){
float PI = 3.14159;
int s1, r = 5;
double s2;
s1 = r * r * PI;
s2 = r * r * PI;
printf("s1=%d, s2=%f\n", s1, s2);
return 0;
}
在計算錶達式r*r*PI
時,r 和 PI 都被轉換成 double 類型,錶達式的結果也是 double 類型。但由於 s1 為整型,所以賦值運算的結果仍為整型,舍去了小數部分,導致數據失真。
强制類型轉換
自動類型轉換是編譯器根據代碼的上下文環境自行判斷的結果,有時候並不是那麼“智能”,不能滿足所有的需求。如果需要,程序員也可以自己在代碼中明確地提出要進行類型轉換,這稱為强制類型轉換。
自動類型轉換是編譯器默默地、隱式地進行的一種類型轉換,不需要在代碼中體現出來;强制類型轉換是程序員明確提出的、需要通過特定格式的代碼來指明的一種類型轉換。換句話說,自動類型轉換不需要程序員幹預,强制類型轉換必須有程序員幹預。
强制類型轉換的格式為: (type_name) expression
type_name為新類型名稱,expression為錶達式。例如:
(float) a; //將變量 a 轉換為 float 類型
(int)(x+y); //把錶達式 x+y 的結果轉換為 int 整型
(float) 100; //將數值 100(默認為int類型)轉換為 float 類型
下面是一個需要强制類型轉換的經典例子:
#include <stdio.h>
int main(){
int sum = 103; //總數
int count = 7; //數目
double average; //平均數
average = (double) sum / count;
printf("Average is %lf!\n", average); //Average is 14.714286!
return 0;
}
sum 和 count 都是 int 類型,如果不進行幹預,那麼sum / count的運算結果也是 int 類型,小數部分將被丟弃;雖然是 average 是 double 類型,可以接收小數部分,但是心有餘力不足,小數部分提前就被“閹割”了,它只能接收到整數部分,這就導致除法運算的結果嚴重失真。
既然 average 是 double 類型,為何不充分利用,盡量提高運算結果的精度呢?為了達到這個目標,我們只要將 sum 或者 count 其中之一轉換為 double 類型即可。上面的代碼中,我們將 sum 强制轉換為 double 類型,這樣sum / count的結果也將變成 double 類型,就可以保留小數部分了,average 接收到的值也會更加精確。
在這段代碼中,有兩點需要注意:
- 對於除法運算,如果除數和被除數都是整數,那麼運算結果也是整數,小數部分將被直接丟弃;如果除數和被除數其中有一個是小數,那麼運算結果也是小數。
- ( )的優先級高於/,對於錶達式(double) sum / count,會先執行(double) sum,將 sum 轉換為 double 類型,然後再進行除法運算,這樣運算結果也是 double 類型,能够保留小數部分。注意不要寫作(double) (sum / count),這樣寫運算結果將是 3.000000,仍然不能保留小數部分。
類型轉換只是臨時性的
無論是自動類型轉換還是强制類型轉換,都只是為了本次運算而進行的臨時性轉換,轉換的結果也會保存到臨時的內存空間,不會改變數據本來的類型或者值。請看下面的例子:
#include <stdio.h>
int main() {
double total = 400.8; //總價
int count = 5; //數目
double unit; //單價
int total_int = (int)total; //400
unit = total / count; // 80.160000
printf("total=%lf, total_int=%d, unit=%lf\n", total, total_int, unit); //total=400.800000, total_int=400, unit=80.160000
return 0;
}
通過上面的代碼,我們能看出來,total雖然轉換了類型給了total_int ,但是total 原本的數據類型沒有發生變化,所以最後計算的時候還是小數 ,也就錶明類型轉換只是占時的只是作用在當前的計算
自動類型轉換 VS 强制類型轉換
在C語言中,有些類型既可以自動轉換,也可以强制轉換,例如 int 到 double,float 到 int 等;而有些類型只能强制轉換,不能自動轉換,例如以後將要學到的 void * 到 int *,int 到 char * 等。
可以自動轉換的類型一定能够强制轉換,但是,需要强制轉換的類型不一定能够自動轉換。現在我們學到的數據類型,既可以自動轉換,又可以强制轉換,以後我們還會學到一些只能强制轉換而不能自動轉換的類型。
可以自動進行的類型轉換一般風險較低,不會對程序帶來嚴重的後果,例如,int 到 double 沒有什麼缺點,float 到 int 頂多是數值失真。只能强制進行的類型轉換一般風險較高,或者行為匪夷所思,例如,char * 到 int * 就是很奇怪的一種轉換,這會導致取得的值也很奇怪,再如,int 到 char * 就是風險極高的一種轉換,一般會導致程序崩潰。 使用强制類型轉換時,程序員自己要意識到潜在的風險。
边栏推荐
- deno debugger
- The basic syntax of mermaid in typera
- DM8 command line installation and database creation
- C语言-入门-基础-语法-[变量,常亮,作用域](五)
- Codeforces Round #793 (Div. 2)(A-D)
- Take you to master the formatter of visual studio code
- High order phase difference such as smear caused by myopic surgery
- 微服务入门:Gateway网关
- Codeforces Round #750 (Div. 2)(A,B,C,D,F1)
- Azure ad domain service (II) configure azure file share disk sharing for machines in the domain service
猜你喜欢
DM8 tablespace backup and recovery
How to play dapr without kubernetes?
What sparks can applet container technology collide with IOT
Leetcode topic [array] -136- numbers that appear only once
4 small ways to make your Tiktok video clearer
Codeforces Global Round 21(A-E)
How to solve the problem that computers often flash
OpenFeign 服务接口调用
What exactly is DAAS data as a service? Don't be misled by other DAAS concepts
09 softmax regression + loss function
随机推荐
Codeforces Round #803 (Div. 2)(A-D)
Awk from entry to penetration (6) regular matching
Turn: excellent managers focus not on mistakes, but on advantages
Group programming ladder race - exercise set l2-002 linked list de duplication
Webapi interview question summary 01
A method for detecting outliers of data
Industry depression has the advantages of industry depression
如何通过antd的upload控件,将图片以文件流的形式发送给服务器
2022 gas examination registration and free gas examination questions
Basic discipline formula and unit conversion
DM8 command line installation and database creation
MySQL relearn 1-centos install mysql5.7
Manjaro install wechat
C语言-入门-基础-语法-[变量,常亮,作用域](五)
Codeforces Round #750 (Div. 2)(A,B,C,D,F1)
How does Xiaobai buy a suitable notebook
AcWing 244. Enigmatic cow (tree array + binary search)
微服務入門:Gateway網關
Openfeign service interface call
Bishi blog (13) -- oral arithmetic test app