C語言學習——數據類型

1.有名有姓的C
編程時給變量或者函數起的名字就是標識符,就好比我們慕課網的每一位童鞋都有姓名,姓名就是這位童鞋的標識符。C語言的標識符是不可以隨便起名字的,必須遵守一定的規則。
C 語言規定,標識符可以是字母(A~Z,a~z)數字(0~9)下劃線_組成的字符串,並且第一個字符必須是字母或下劃線。在使用標識符時還有注意以下幾點:
(1)標識符的長度最好不要超過8位,因爲在某些版本的C中規定標識符前8位有效,當兩個標識符前8位相同時,則被認爲是同一個標識符。 
(2)標識符是嚴格區分大小寫的。例如Imooc和imooc 是兩個不同的標識符。 
(3)標識符最好選擇有意義的英文單詞組成做到"見名知意",不要使用中文。
(4)標識符不能是C語言的關鍵字。想了解更多C語言關鍵字的知識,請查閱WIKI。
例如:

2.變量及賦值
變量就是可以變化的量,而每個變量都會有一個名字(標識符)。變量佔據內存中一定的存儲單元。使用變量之前必須先定義變量,要區分變量名和變量值是兩個不同的概念。就好比:住在房間裏的客人與房間號是兩個不同的概念。
變量定義的一般形式爲:數據類型 變量名;
多個類型相同的變量:數據類型 變量名, 變量名, 變量名...;
變量名和標識符的命名規範完全相同。%d在後面會有詳細講解
注意:在定義中不允許連續賦值,如int a=b=c=5;是不合法的。
變量的賦值分爲兩種方式:1.先聲明再賦值  2.聲明的同時賦值,例如:

3.基本數據類型
在我們玩遊戲的時候,遊戲中的角色是有類型的,有敏捷型、力量型、法術型等等。同樣C語言中的數據也是有類型的,C語言中,數據類型可分爲:基本數據類型,構造數據類型,指針類型,空類型四大類。如圖所示: 
這裏我們先給大家講解基本數據類型中最簡單也是最常用的整型、實型與字符型
整型數據是指不帶小數的數字。生活中有很多信息適合使用整型數據來表示,比如:人的年齡、班級的人數、書的總頁數等等。因此整型的類型比較多:
注:int、short int、long int是根據編譯環境的不同,所取範圍不同。而其中short int和long int至少是表中所寫範圍,但是int在表中是以16位編譯環境寫的取值範圍。另外 c語言int的取值範圍在於他佔用的字節數 ,不同的編譯器,規定是不一樣。ANSI標準定義int是佔2個字節,TC是按ANSI標準的,它的int是佔2個字節的。但是在VC裏,一個int是佔4個字節的。
浮點數據是指帶小數的數字。生活中有很多信息適合使用浮點型數據來表示,比如:人的體重(單位:公斤)、商品價格、圓周率等等。因爲精度的不同又分爲3種:
注:C語言中不存在字符串變量,字符串只能存在字符數組中,這個後面會講。
在C語言標準庫頭文件float.h定義了浮點數小數點後的有效位數 :
1
2
3
4
    //float.h頭文件的部分代碼
    #define DBL_DIG 15    //雙精度小數點後15位
  #define FLT_DIG 6     //單精度小數點後6位
  #define LDBL_DIG 19   //長雙精度小數點19
補充:
16位編譯器
char :1個字節
char*(即指針變量): 2個字節
short int : 2個字節
int: 2個字節
unsigned int : 2個字節
float: 4個字節
double: 8個字節
long: 4個字節
long long: 8個字節
unsigned long: 4個字節
32位編譯器
char :1個字節
char*(即指針變量): 4個字節(32位的尋址空間是2^32, 即32個bit,也就是4個字節。同理64位編譯器)
short int : 2個字節
int: 4個字節
unsigned int : 4個字節
float: 4個字節
double: 8個字節
long: 4個字節
long long: 8個字節
unsigned long: 4個字節

64位編譯器
char :1個字節
char*(即指針變量): 8個字節
short int : 2個字節
int: 4個字節
unsigned int : 4個字節
float: 4個字節
double: 8個字節
long: 8個字節
long long: 8個字節
unsigned long: 8個字節

4.格式化輸出語句
格式化輸出語句,也可以說是佔位輸出,是將各種類型的數據按照格式化後的類型及指定的位置從計算機上顯示。這樣做的好處,是有利於計算機能夠準確的將我們所要類型數據給我們。
其格式爲:printf("輸出格式符",輸出項);
C語言中的常用格式化符:
當輸出語句中包含普通字符時,可以採用一下格式:
printf("普通字符輸出格式符", 輸出項);
例如:
輸出結果爲: a=10 
如果要輸出多個變量的並指定變量的位置時候,格式符還可以連用,變量之間需要用逗號隔開,如:
輸出結果爲: 整數:10,小數:7.560000,字符:c ,若%.2f則表示兩位小數
注意:格式符的個數要與變量、常量或者表達式的個數一一對應     

5.不可改變的常量
在程序執行過程中,值不發生改變的量稱爲常量。C語言的常量可以分爲直接常量和符號常量
直接常量也稱爲字面量,是可以直接拿來使用,無需說明的量,比如:
  • 整型常量:13、0、-13;
  • 實型常量:13.33、-24.4;
  • 字符常量:‘a’、‘M’
  • 字符串常量:”I love imooc!”
下面的代碼分別打印這四種直接常量:
在C語言中,可以用一個標識符來表示一個常量,稱之爲符號常量。符號常量在使用之前必須先定義,其一般形式爲:
 #define 標識符 常量值 
符號常量的標示符一般習慣使用大寫字母,變量的標示符一般習慣使用小寫字母,加以區分。下面是一個使用符號常量的小例子:
運算結果爲: 圓周率:3.140000 
注意:常量是不可改變的

6.自動類型轉換
有這麼一個詞叫“狸貓換太子”,變量的數據類型就存在這樣的情況。數據類型存在自動轉換的情況,比如:
自動轉換髮生在不同數據類型運算時,在編譯的時候自動完成。自動轉換遵循的規則就好比小盒子可以放進大盒子裏面一樣,下圖表示了類型自動轉換的規則。
char類型數據轉換爲int類型數據遵循ASCII碼中的對應值,ASCII碼請查看WIKI。
注:字節小的可以向字節大的自動轉換,但字節大的不能向字節小的自動轉換

自動類型轉換
自動類型轉換就是編譯器默默地、隱式地、偷偷地進行的數據類型轉換,這種轉換不需要程序員干預,會自動發生。

1) 將一種類型的數據賦值給另外一種類型的變量時就會發生自動類型轉換,例如:
float f = 100;
100 是 int 類型的數據,需要先轉換爲 float 類型才能賦值給變量 f。再如:
int n = f;
f 是 float 類型的數據,需要先轉換爲 int 類型才能賦值給變量 n。

在賦值運算中,賦值號兩邊的數據類型不同時,需要把右邊表達式的類型轉換爲左邊變量的類型,這可能會導致數據失真,或者精度降低;所以說,自動類型轉換並不一定是安全的。對於不安全的類型轉換,編譯器一般會給出警告。

2) 在不同類型的混合運算中,編譯器也會自動地轉換數據類型,將參與運算的所有數據先轉換爲同一種類型,然後再進行計算。轉換的規則如下:
  • 轉換按數據長度增加的方向進行,以保證數值不失真,或者精度不降低。例如,int 和 long 參與運算時,先把 int 類型的數據轉成 long 類型後再進行運算。
  • 所有的浮點運算都是以雙精度進行的,即使運算中只有 float 類型,也要先轉換爲 double 類型,才能進行運算。
  • char 和 short 參與運算時,必須先轉換成 int 類型。

下圖對這種轉換規則進行了更加形象地描述:
unsigned 也即 unsigned int,此時可以省略 int,只寫 unsigned。
7.強制類型轉換
強制類型轉換是通過定義類型轉換運算來實現的。其一般形式爲:
 (數據類型) (表達式) 
其作用是把表達式的運算結果強制轉換成類型說明符所表示的類型,例如:
輸入結果:
在使用強制轉換時應注意以下問題:
1、數據類型和表達式都必須加括號,如把(int)(x/2+y)寫成(int)x/2+y則成了把x轉換成int型之後再除2再與y相加了。
2、轉換後不會改變原數據的類型及變量值,只在本次運算中臨時性轉換
3、強制轉換後的運算結果不遵循四捨五入原則

強制類型轉換
自動類型轉換是編譯器根據代碼的上下文環境自行判斷的結果,有時候並不是那麼“智能”,不能滿足所有的需求。如果需要,程序員也可以自己在代碼中明確地提出要進行類型轉換,這稱爲強制類型轉換。

自動類型轉換是編譯器默默地、隱式地進行的一種類型轉換,不需要在代碼中體現出來;強制類型轉換是程序員明確提出的、需要通過特定格式的代碼來指明的一種類型轉換。換句話說,自動類型轉換不需要程序員干預,強制類型轉換必須有程序員干預。

強制類型轉換的格式爲:
(type_name) expression
type_name爲新類型名稱,expression爲表達式。例如:
  1. (float) a; //將變量 a 轉換爲 float 類型
  2. (int)(x+y); //把表達式 x+y 的結果轉換爲 int 整型
  3. (float) 100; //將數值 100(默認爲int類型)轉換爲 float 類型
下面是一個需要強制類型轉換的經典例子:
  1. #include <stdio.h>
  2. int main(){
  3. int sum = 103; //總數
  4. int count = 7; //數目
  5. double average; //平均數
  6. average = (double) sum / count;
  7. printf("Average is %lf!\n", average);
  8. return 0;
  9. }
運行結果:
Average is 14.714286!

sum 和 count 都是 int 類型,如果不進行干預,那麼sum / count的運算結果也是 int 類型,小數部分將被丟棄;雖然是 average 是 double 類型,可以接收小數部分,但是心有餘力不足,小數部分提前就被“閹割”了,它只能接收到整數部分,這就導致除法運算的結果嚴重失真。

既然 average 是 double 類型,爲何不充分利用,儘量提高運算結果的精度呢?爲了達到這個目標,我們只要將 sum 或者 count 其中之一轉換爲 double 類型即可。上面的代碼中,我們將 sum 強制轉換爲 double 類型,這樣sum / count的結果也將變成 double 類型,就可以保留小數部分了,average 接收到的值也會更加精確。

在這段代碼中,有兩點需要注意:
  • 對於除法運算,如果除數和被除數都是整數,那麼運算結果也是整數,小數部分將被直接丟棄;如果除數和被除數其中有一個是小數,那麼運算結果也是小數。這一點已在《C語言加減乘除運算》中進行了詳細說明。
  • ( )的優先級高於/,對於表達式(double) sum / count,會先執行(double) sum,將 sum 轉換爲 double 類型,然後再進行除法運算,這樣運算結果也是 double 類型,能夠保留小數部分。注意不要寫作(double) (sum / count),這樣寫運算結果將是 3.000000,仍然不能保留小數部分。
類型轉換隻是臨時性的
無論是自動類型轉換還是強制類型轉換,都只是爲了本次運算而進行的臨時性轉換,轉換的結果也會保存到臨時的內存空間,不會改變數據本來的類型或者值。請看下面的例子:
  1. #include <stdio.h>
  2. int main(){
  3. double total = 400.8; //總價
  4. int count = 5; //數目
  5. double unit; //單價
  6. int total_int = (int)total;
  7. unit = total / count;
  8. printf("total=%lf, total_int=%d, unit=%lf\n", total, total_int, unit);
  9. return 0;
  10. }
運行結果:
total=400.800000, total_int=400, unit=80.160000

注意看第 6 行代碼,total 變量被轉換成了 int 類型才賦值給 total_int 變量,而這種轉換並未影響 total 變量本身的類型和值。如果 total 的值變了,那麼 total 的輸出結果將變爲 400.000000;如果 total 的類型變了,那麼 unit 的輸出結果將變爲 80.000000。
自動類型轉換 VS 強制類型轉換
在C語言中,有些類型既可以自動轉換,也可以強制轉換,例如 int 到 double,float 到 int 等;而有些類型只能強制轉換,不能自動轉換,例如以後將要學到的 void * 到 int *,int 到 char * 等。

可以自動轉換的類型一定能夠強制轉換,但是,需要強制轉換的類型不一定能夠自動轉換。現在我們學到的數據類型,既可以自動轉換,又可以強制轉換,以後我們還會學到一些只能強制轉換而不能自動轉換的類型。

可以自動進行的類型轉換一般風險較低,不會對程序帶來嚴重的後果,例如,int 到 double 沒有什麼缺點,float 到 int 頂多是數值失真。只能強制進行的類型轉換一般風險較高,或者行爲匪夷所思,例如,char * 到 int * 就是很奇怪的一種轉換,這會導致取得的值也很奇怪,再如,int 到 char * 就是風險極高的一種轉換,一般會導致程序崩潰。

使用強制類型轉換時,程序員自己要意識到潛在的風
發佈了27 篇原創文章 · 獲贊 85 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章