在上一篇文章中我們通過一個經典的C語言入門程序認識了C語言,算是一個小小的入門,也是我對C語言的一次系統的復習,講的可能不夠詳細,在接下來的文章中我將盡可能詳細的講述我在學習C語言基礎的過程中接觸到的知識點,本篇文章主要講述C語言中的數據類型。
同樣我們先引入一個例子,代碼如下:
include <stdio.h>
include <malloc.h>
int main()
{
int age; //定義一個名為age的整數型變量,用于存放年齡
double weight,height; //定義一個名為weight和一個名為height的雙精度浮點型變量,用于存放體重和年齡
float salary; //定義一個單精度浮點型變量,用于存放工資
char name[8]; //定義一個8字節的字符數組,用于存放姓名(注意一個中文字符占兩個字節,因此該變量中最多可存放四個中文字符,而一個英文字符占用一個字節,因此這里可存放8個英文字符)
char *motto; //定義一個字符指針,該指針指向字符常量或字符串常量,用于存放座右銘
printf("Please enter your name\n");//打印字符串,上一篇文章中已經說過一部分
scanf("%s",name); //從控制臺讀取字符串,并存到字符數組name中(注意讀取字符串時變量前不加&符號,而讀取其他類型變量時需要加&符號,關于&符號的解釋及地址相關的內容會在以后的文章中提到)
printf("Plese enter your age\n");
scanf("%d",&age); //從控制能讀取一個整數,并存到age中,這里的age變量前有&符號
printf("Please enter your salary!\n");
scanf("%f",&salary);
printf("Please enter your height and weight!\n");
scanf("%lf %lf",&height,&weight);
printf("Please enter your motto!\n");
motto = malloc(sizeof(char) * 20);//分配內存空間,用char *x定義的變量必須分配空間才能使用,sizeof()函數用來取得當前類型或變量的長度,即占用字節數
scanf("%s",motto);
printf("Name:%s\nAge:%d\nHeight:%.2lf\nWeight:%.2lf\nSalary:%.2f\nMotto:%s\n",name,age,height,weight,salary,motto);//上次提到printf()函數是參數數量可變的函數,這里的參數數量是任意的,與要格式化的占位符一一對應
free(motto);
return 0;
}
前兩行為頭文件的引入,stdio.h文件在Helloworld的例子中已經說過,它是標準輸入輸出相關的頭文件,malloc.h是第一次遇到,這個頭文件主要包含了C語言內存分配相關的函數的聲明,例如上面例子上用到的malloc()和free()兩個函數,malloc()函數是內存分配函數,該函數接收一個參數,該參數為要分配內存的字節數,內存分配是匿名的,maclloc()函數在內存中找到合適大小的位置后會返回該塊內存的第一個字節的地址,但如果malloc()找不到合適空間,則會返回空指針。一般來說malloc()函數帶用于動態分配內存,即在運行時決定,如下面的例子:
int n = rand() % 100;
char name[n];
這在C99之前是不被支持的,而用malloc()函數可成功分配到內存:
int n = rand() % 100;
char name = malloc(sizeof(char) * n);
這里有一個sizeof()的函數,這個函數的作用是用來取某一類型的大小或某一具體量的大小,這里的大小指的是字節數,如char 占用一個字節,int占用4個字節,float占用4個字節,double占用8個字節,char、int、float、double*在64位系統中都是占用4個字節等。該函數在取類型占用的字節時參數必須用圓括號包圍,即必須是sizeof(char)的形式,而在取具體變量的長度時則可以不用括號,如
char name[8];
printf("%d",sizeof name);
這里將打印出8,不過筆者推薦在所有情況下都加上圓括號,以免出現奇怪的問題,同時也可增強代碼可讀性
接著向下看,第三行語句
int age;
這里的int 是integer的意思,即這是一個整數類型的變量,它占用4個字節,它是一個有符號的整數變量,因此符號位占用一位,在32位系統中取值范圍在-2^31 ~ 2^31 -1之間,也就是可存儲值的大小為2^32。
整數相關的基本數據類型還有短整數類型short,它在系統中占用2個字節,每個字節占8位,因此取值范圍在 -2^15 ~ 2^15 -1;長整數類型long,在系統中占用8個字節因此取值范圍為-263~263-1,無符號短整數類型unsigned short,占用字節數與short是相同的,但由于沒有符號位因此取值范圍為0 ~ 2^16 -1。同理無符號整型unsigned int 取值范圍為 0 ~ 2^32 -1,無符號長整數類型unsigned long 取值范圍為0 ~ 2 ^64 -1,因為long long 也占用8個字節,因此long long 與long 的取值范圍相同,unsigned long long 與 unsigned long取值范圍相同。
double weight,height;
float salary;
double為雙精度浮點型,相比float(單精度浮點型)存儲的數據更準確,占用的空間也大一倍,單精度浮點數在機器中占用4個字節,占32位;雙精度浮點數占用8位,點64位。浮點數在系統內是用指數形式存儲,分為數符,尾數,指數符,指數四部分組成;數符即符號位占一位,表示正負,指數符即指數符號位,表示指數的正負。尾數表示浮點數的有效數字,指數位存放指數的有效數字。一般的float類型尾數點24位指數點8位,double類型尾數點48位,指數點16位。在C語言中float可保存有效數字7位,double可保存有效數字15位,double的內存消耗是float的兩倍,double數據的計算速度也比float慢的多,因此,要根據實際情況來決定是否用double,如果數據不會溢出盡量使用float類型,在本例中定義的weight,height兩個變量就應該使用float。
char name[8];
char 即character,字符的意思,char在內存中只占用一個字節,一般用來存放字母、標點等。嚴格來講,其實char也是整數類型,因為char保存的其實就是一個整數,計算機通過ASCII編碼方式來將某個字符保存為一個整數,ASCII碼的范圍是0 ~ 127 只需要7位就可以保存,而char型數據占用8位,足以保存全部的ASCII值。 這里的name[8]代表一個可保存8位char型數據的數組。這里的數據是一塊連續的存儲空間,方括號里的數字為數組的下標,表示這8位連續空間的編號,在C語言中數組的下標是從0開始的,因此在存儲的時候最后一個有效元素的下標為7,例如"c is ammizing"一共有13個字符(空格也算在其中),但它將占用14個字節,最后一個字節用來存放"\0",這里的"\0"是系統自動添加的。
char *motto;
代表指針,指針是一個變量,這個變量用于指向另一個變量所在內存中的位置,這里的motto是一個指向char型變量或數組的指針,它里面只保存了這個char型變量或char型數組首元素的地址,而motto中存放的是才是變量的值。在下面這句
motto = malloc(sizeof(char) * 20);
是用來給這個char型變量或數組分配內存的語句,上面已經提到過的malloc語句,它將這個char型數組的首地址存到motto這個變量中。在C語言中指針是一門藝術,指針使用不當往往會也遇到很多問題,本文不打算深究C語言指針方面的知識,如果您對這方面感興趣可以看一下《C和指針》(英文名《Pointers on C》By Kenneth A. Reek)。
scanf("%s",name);
scanf("%d",&age);
scanf("%lf %lf",&height,&weight);
scanf("%s",motto);
這幾條語句的作用是從控制臺讀取值存入相應的變量中,scanf()也是一個參數數量可變的函數,每一個參數與相應的占位符對應。但注意到在讀取字符串值存到char數組或char *類型的變量中時是沒有&符號的,其他就是都要加一個&符號,這里的&符號是用來取到該變量的首地址的,因為數組的首就是數組的第一個元素,而數組變量本身就代表數組的第一個元素因此不加&符號,對于指針型變量也是相同道理,指針型變量本身就指向這塊內存的首地址,因此也不用加&符號。(這里"%s"對應字符串或字符數組,"%d"對應整數類型,"%lf"對應double類型,"f"對應float類型,還有"%c"對應char類型等)。
總結:
C語言中的基本數據類型分為數值型和字符型兩大類,數值型又分為整型和浮點型兩類,整型又分:短整型(short),整型(int),長整型(long)三類,浮點型又分為:單精度浮點型(float)和雙精度浮點型(double)兩類。C語言的數據類型還包括構造類型,指針類型和空類型三類,這三類在以后會慢慢接觸到。
要注意的時每種數據類型對應的取值范圍,在選擇數據類型的時候一定要考慮到當前要存儲的數據最大值和最小值能達到多少,再來選擇相應的數據類型存儲,在使用指針動態分配內存的時候一定要在用完之后第一時間釋放內存,否則可能會導致這塊內存一直被占用無法被其他應用或進程訪問,即造成內存泄漏。