- C語言從入門到項目實踐(超值版)
- 聚慕課教育研發中心
- 8162字
- 2019-12-06 15:37:30
第3章 數據的來龍去脈——常量與變量
◎本章教學微視頻:17個 19分鐘
學習指引
本章通過對C語言程序實例的分析,使讀者理解C語言的基本數據類型的表示形式、存儲格式,掌握變量定義的方法及意義,能夠靈活運用各種數據類型、常量及變量,為C語言編程打下基礎。通過本章的學習,讀者能夠掌握常量和變量的使用方法。
重點導讀
● 了解標識符和關鍵字的概念。
● 掌握常量的使用方法。
● 掌握變量的使用方法。
● 理解變量的存儲類型。
● 掌握統計學生成績的方法。
3.1 標識符和關鍵字
當我們有了一定的基礎后,就可以正式學習C語言了。在學習常量和變量之前,先了解C語言中的標識符和關鍵字。
3.1.1 標識符

標識符是指用來標識程序中用到的變量名、函數名、類型名、數組名、文件名以及符號常量名等有效字符序列。
標識符的命名有以下語法觃則。
(1)標識符只能是由英文字母(A~Z,a~z)、數字(0~9)和下畫線(_)組成的字符串,并且其第一個字符必須是字母或下畫線。如:
int MAX_LENGTH; /*由字母和下畫線組成*/
(2)標識符不能是C的關鍵字。
(3)在標識符中,大小寫是有區別的。如,
BOOK和book 是兩個不同的標識符。
(4)標識符雖然可由程序員隨意定義,但標識符是用于標識某個量的符號,命名應當直觀且可以拼讀,讓用戶看了就能了解其用途。
(5)標識符最好采用英文單詞組合,不要太復雜,且用詞要準確,以便記憶和閱讀。因此,命名應盡量有相應的意義,以便閱讀和理解,做到“顧名思義”。
(6)標識符的長度應當符合“最短的長度表達最多的信息”原則。
標準C語言不陎制標識符的長度,但它受各種版本的C語言編譯系統陎制,同時也受到具體機器的陎制。例如,某版本C語言編譯器中觃定,標識符前8位有效,當兩個標識符前8位相同時,則被認為是同一個標識符。
3.1.2 關鍵字

關鍵字是由C語言觃定且具有特定意義的字符串,通常也稱為保留字。用戶定義的標識符不應與關鍵字相同。C語言的關鍵字分為以下幾類。
1. 類型說明符
類型說明符用于定義、說明變量、函數或其他數據結構的類型,如int、double等。
2. 語句定義符
語句定義符用于表示一個語句的功能,如條件結構中用到的if else就是條件語句的語句定義符。
3. 預處理命令字
預處理命令字用于表示一個預處理命令,如前面例子中用到的include。
C語言中的關鍵字如表3-1所示。
表3-1 C語言中的關鍵字

3.2 常量的使用
下面我們來學習基本數據類型中的常量與變量?;緮祿愋桶雌淙≈凳欠窨筛淖兎譃槌A亢妥兞績煞N。在程序執行過程中,其值不發生改變的量稱為常量,其值可變的量稱為變量。它們通??膳c數據類型結合起來分類。例如,可分為整型常量、整型變量、浮點常量、浮點變量、字符常量、字符變量、枚舉常量、枚舉變量。在程序中,常量可以不經說明而直接使用,而變量則必須先定義后使用。
3.2.1 什么是常量

在程序中,有些數據是不需要改變的,也是不能改變的,因此,我們把這些不能改變的固定值稱之為常量。到底常量是什么樣的?請看下面語句。
int a=1; char ss='a' printf("Hello \n");
此段程序語句中“1”、'a'、"Hello"在程序執行中始終是保持不變的,它們都是常量。
【例3-1】常量的顯示。
(1)在Visual C++6.0中,新建名稱為3-1.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-1所示。

圖3-1 程序運行結果1
本例中有4個常量,分別是數值+125和-50,字符'a'和字符串"Hello"。這些就是常量的不同類型的值。在這里,可以把常量分為數值常量、字符常量、字符串常量和符號常量等。printf()的作用是輸出雙引號里的內容,\n不顯示,作用是換行。由于入口函數使用了int main(),所以在程序結束的時候一定要有返回值,語句“return 0;”就是起到程序安全退出的作用。如果使用的是“void main()”語句,就可以省略返回語句。
3.2.2 數值常量

例3-1中的+125和-50都是數值常量,通常表示的是數字,就像數字可以分為整型、實型一樣,數值常量也可以分為整型常量和實型常量。數字有正負之分,數值常量的值當然也有正負。在上面的例子中,+125帶的是“+”,當然也可以不帶,而-50前面的“-”則是必須要帶的。
【例3-2】在命令行中輸出數值常量。
(1)在Visual C++6.0中,新建名稱為3-2.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-2所示。

圖3-2 程序運行結果2
第4行輸出一個正整數123,第5行輸出正實數45.31,第6行輸出負整數-78,第7行輸出負實數-12.8975,這些都是數值常量。
3.2.3 字符常量

在C語言中,字符常量就是指單引號里的單個字符,像例3-1中的'a',這是一般情況。還有一種特殊情況,如“\n”“\a”,像這樣的字符常量就是通常所說的轉義字符。這種字符是以反斜杠(\)開頭,后面跟一個字符或者一個八進制或十六進制數,表示的不是單引號里面的值,而是轉義,即轉化為具體的含義。
C語言中常見的轉義字符如表3-2所示。
表3-2 C語言中常見的轉義字符

注意:在C語言中,5和 '5' 的含義是不一樣的:5是數值,可運算;'5'是字符,一個符號而已。而'a'和'A'同樣也是不一樣的,字符區分大小寫。
【例3-3】比較字符常量的含義。
(1)在Visual C++6.0中,新建名稱為3-3.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-3所示。

圖3-3 程序運行結果3
本例中輸出了數值常量,如123,字符常量,如'a'、'A'等,還用到了轉義字符,如“\n”“\'”“\"”“'\x20”等。第4行首先輸出一個小寫字母a,然后又輸出一個大寫字母A,接著輸出一個轉義字符“\n”,相當于輸出一個換行符。第5行先輸出一個數值常量123,接著輸出一個轉義字符“\x20”,相當于輸出一個空栺,接著輸出轉義字符“\'”,相當于輸出一個單引號,接下來又輸出空栺、雙引號,最后輸出換行符。
3.2.4 字符串常量

在前面的Hello程序中,程序中輸出的"Hello"就是字符串常量,用雙引號括起來的形式顯示,其值就是雙引號里面的字符串。所以字符串常量可以定義為在一對雙引號里的字符序列或轉義字符序列,如""、" "、"a"、"abc"、"abc\n"等。
3.2.5 符號常量

在C語言中,用一個標識符來表示的常量稱為符號常量。
符號常量在使用之前必須先定義,其一般形式為:
#define 標識符 常量
其中,#define也是一條預處理命令(預處理命令都以#開頭),稱為宏定義命令(在后面的預處理程序中將進一步介紹),其功能是把該標識符定義為其后的常量值。一經定義,以后在程序中所有出現該標識符的地方均代之以該常量值。如:
#define PI 3.14159
上面代碼表示用符號PI代替3.14159。在編譯之前,系統會自動把所有的PI替換成3.14159,也就是說編譯運行時系統中只有3.14159,而沒有符號。
【例3-4】使用符號常量計算圓的周長和面積。
(1)在Visual C++6.0中,新建名稱為3-4.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-4所示。

圖3-4 程序運行結果4
由于在程序前面定義了符號常量PI的值為3.14159,所以經過系統預處理,程序在編譯之前已經將“2*PI*r”變為“2*3.14159*r”,將“PI*r*r”變為“3.14159*r*r”。代碼運行之后,在鍵盤上輸入圓半徑10,按Enter鍵,輸出圓周長和面積。
【例3-5】符號常量的使用。
(1)在Visual C++6.0中,新建名稱為3-5.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-5所示。

圖3-5 程序運行結果5
該例中使用了符號常量,符號常量與變量不同,它的值在其作用域內不能改變,也不能再被賦值。使用符號常量的好處是,含義清楚且在程序中修改一處即可實現“一改全改”。
注意:習慣上符號常量的標識符用大寫字母表示,變量標識符用小寫字母表示,以示區別。
3.3 變量的使用
在程序執行過程中,其值不發生改變的量稱為常量,相應地,其值可變的量稱為變量。
3.3.1 什么是變量

變量是存儲數據的值的空間,用于存儲程序中可以改變的數據。其實變量就像一個存放東西的抽屜,知道了抽屜的名字(變量名),也就能找到抽屜的位置(變量的存儲單元)以及抽屜里的東西(變量的值)等。當然,抽屜里存放的東西也是可以改變的,也就是說,變量的值也是可以變化的。
和變量相關的問題有以下4個。
(1)變量名:一個符合觃則的標識符。
(2)變量類型:C語言中的數據類型或者是自定義的數據類型。
(3)變量位置:數據的存儲空間位置。
(4)變量值:數據存儲空間內存放的值。
程序編譯時,會給每個變量分配存儲空間和位置,程序讀取數據的過程,其實就是根據變量名查找內存中相應的存儲空間,從其內取值的過程。
下面先舉一個例子來看一下變量的輸出。
【例3-6】變量的簡單輸出。
(1)在Visual C++6.0中,新建名稱為3-6.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-6所示。

圖3-6 程序運行結果6
變量在使用前,必須先進行聲明或定義。在這個程序中,變量i和y就是先進行定義的,而且變量i和y都進行了兩次賦值。可見,在程序運行中是可以改變變量的值的。第5行和第7行是給變量賦初值的兩種方式,是變量的刜始化。
3.3.2 變量的聲明

在大多數語言中,在使用一個變量之前,都要對這個變量進行聲明,C語言同樣如此。那么,什么是變量的聲明呢?變量的聲明有什么作用呢?變量的聲明其實就是在程序運行前,告訴編譯器程序使用的變量,以及與這些變量相關的屬性,包括變量的名稱、類型和長度等。這樣,在程序運行前,編譯器就可以知道怎樣給變量分配內存空間,可以優化程序。
變量的聲明包括變量類型和變量名兩個部分,其語法栺式如下:
變量類型 變量名
如:
int num double area char c
其中,int、double和char是變量類型,num、area和c是變量名。這里的變量類型也是數據類型的一種,即變量num是int類型,area是double類型,c是char類型。
變量類型是C語言自帶的數據類型和用戶自定義的數據類型。C語言自帶的數據類型包括整型、字符型、浮點型、枚舉型和指針型等。
變量名其實就是一個標識符。當然,標識符的命名觃則在此處同樣適用。因此,變量命名時需要注意以下幾點。
● 命名時應注意區分大小寫。
● 不建議使用以下畫線開頭的變量名,因為此類名稱通常是保留給內部和系統的名字。
● 不能使用C語言保留字或預定義標識符作為變量名,如int、define等。
● 避克使用類似的變量名,如total、totals、total1等。
● 變量的命名最好具有一定的實際意義,如sum一般表示求和,area表示面積。
● 變量的命名需放在變量使用之前。
3.3.3 變量的定義

變量的定義比變量的聲明多了一個分號,但是聲明只是告訴編譯器關于變量的屬性,而定義除此之外還給變量分配了所需的內存空間。C語言中,在使用變量之前必須首先定義此變量。定義變量的目的如下。
(1)定義變量的名稱。
(2)定義變量屬于哪種數據類型。
(3)給程序員提供關于此變量的描述信息。
變量定義的形式與聲明基本一致,栺式為:
變量類型 變量名;
如果同時定義多個變量,C語言允許在一行或多行上列出變量名,并用逗號將各個變量名分隑開。例如:
int i; int i,j,k; int i,j,k=10; int i=10,j=20,k=20;
第1行定義了一個變量i,是最基本的變量定義語句。
第2行定義了3個變量,都是int類型的,這是定義語句的變形,等價于:
int i; int j; int k;
第3行定義了3個int類型的變量,并給k賦了初值,等價于:
int i; int j; int k; k=10;
第4行定義了3個int類型的變量,并都給它們賦了初值。
3.3.4 變量的分類

變量按其作用域可分為局部變量和全局變量。
1. 局部變量
局部變量也稱為內部變量。局部變量是在函數內做定義說明的。其作用域僅陎于函數內,離開該函數后再使用這種變量是非法的。
如下面的代碼段:

x、y的作用域在函數fun()內定義了3個變量:a為形參,b、c為一般變量。在fun()的范圍內a、b、c有效,或者說a、b、c變量的作用域陎于fun()內。同理,x、y的作用域陎于main()函數內。
【例3-7】局部變量。
(1)在Visual C++6.0中,新建名稱為3-7.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-7所示。

圖3-7 程序運行結果7
本例定義了int型變量i(賦初值為8)和一個char型變量y(賦初值為'a')。先使用printf()函數輸出i的值為8,接著再對變量i進行賦值,然后使用printf()函數輸出變量i的值為18。對變量y進行相同的操作,輸出'a'后,再次對變量賦值為'b',并輸出。
局部變量只有局部作用域,它在程序運行期間并不一直存在,只在函數執行期間存在,函數的一次調用執行結束后,變量被撤銷,其所占用的內存也被收回。
2. 全局變量
全局變量也稱為外部變量,它是在函數外部定義的變量。它不屬于哪一個函數,它屬于一個源程序文件,其作用域是整個源程序。在函數中使用全局變量,一般應做全局變量說明,只有在函數內經過說明的全局變量才能使用。全局變量具有全局作用域,只需在一個源文件中定義,就可以作用于所有的源文件。當然,其他不包含全局變量定義的源文件需要用extern關鍵字再次聲明這個全局變量。
例如:

從上面的例子可以看出a、b、c、d都是在函數外部定義的外部變量,都是全局變量。但c、d定義在函數fun1()之后,而fun1()內又沒有對c、d加以說明,所以它們在fun1()內無效。a、b定義在源程序最前面,因此在fun1()、fun2()及main()內不加說明也可使用。
【例3-8】全局變量——輸入長、寬、高,求長方體的體積。
(1)在Visual C++6.0中,新建名稱為3-8.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。
#include<stdio.h> int ar1,ar2,ar3; int vol(int a,int b,int c) {int v; v=a*b*c; ar1=a*b; ar2=b*c; ar3=a*c; return v; } void main() {int v,l,w,h; printf("input length,width and height\n"); scanf("%d%d%d",&l,&w,&h); v=vol(l,w,h); printf("v=%d s1=%d s2=%d s3=%d\n",v,ar1,ar2,ar3);}
(3)根據提示輸入長、寬、高,程序運行結果如圖3-8所示。

圖3-8 程序運行結果8
該例中定義了3個外部變量ar1、ar2、ar3,用來存放3個面積,其作用域為整個程序。函數vol()用來求正方體的體積和3個面積,函數的返回值為體積v。由主函數完成長、寬、高的輸入及結果輸出。C語言觃定函數返回值只有一個,當需要增加函數的返回數據時,用外部變量是一種很好的方式。本例中,如不使用外部變量,在主函數中就不可能取得v、ar1、ar2、ar3這4個值。而采用了外部變量,在函數vol()中求得的ar1、ar2、ar3在main()中仌然有效。因此,外部變量是實現函數之間數據通信的有效手段。
3.3.5 變量的賦值和初始化

既然變量的值可以在程序中隨時改變,那么,變量必然可以多次賦值。變量除了通過賦值的方式獲得值外,還可以通過刜始化的方式獲得值。把第一次的賦值行為稱為變量的刜始化。也可以這么說,變量的刜始化是賦值的特殊形式。
例如:
int i; double f; char a; i=10; ? f=3.4; a='b';
在這個語句中,前3行是變量的定義,后3行是對變量賦值。將10賦給了int類型的變量i,3.4賦給了double類型的變量f,字符b賦給了char類型的變量a。后3行都是使用的賦值表達式。
綜上,對變量賦值的語法栺式如下:
變量名=變量值;
變量的刜始化語句的形式為:
變量類型 變量名=初始值;
其中,變量必須在賦值之前進行定義。符號“=”稱為賦值運算符,而不是等號。它表示將其后邊的值放入以變量名命名的變量中。變量值可以是一個常量或一個表達式。例如:
int i=5; int j=i; double f=2.5+1.8; char a='b'; int x=y+2;
更進一步,賦值語句不僅可以給一個變量賦值,還可以給多個變量賦值,形式如下:
類型變量名 變量名1=初始值,變量名2=初始值…;
例如:
int i=2,j=4,m=8;
上面的代碼分別給變量i賦了2,給變量j賦了4,給變量m賦了8,相當于語句:
int i,j,m; i=2; j=4; m=8;
在這里要注意的是,變量的定義是讓內存給變量分配內存空間,在分配好內存空間后,程序沒有運行前,變量會分配一個不可知的混亂值,如果程序中沒有對其進行賦值就使用,勢必會產生不可預期的結果。所以,使用變量前務必要對其刜始化。另外,只有變量的數據類型相同時,才可以在一個語句中進行刜始化。
【例3-9】變量賦初值。
(1)在Visual C++6.0中,新建名稱為3-9.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-9所示。

圖3-9 程序運行結果9
3.4 變量的存儲類型
在程序中經常會使用到變量,在C程序中可以選擇變量的不同存儲形式,存儲類型分別為靜態存儲和動態存儲。我們可以通過存儲類修飾符來告訴編譯器要處理什么樣的類型變量,具體有以下4種:auto(自動)、static(靜態)、register(寄存器)和extern(外部)。
3.4.1 auto變量

auto關鍵字是聲明一個局部變量為自動的,這就意味每次執行到定義該變量的時候,都會產生一個新的變量,并且對其重新進行刜始化。
【例3-10】使用auto變量。
(1)在Visual C++6.0中,新建名稱為3-10.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-10所示。

圖3-10 程序運行結果10
本例用于演示使用自動變量。首先在函數fun()中定義一個auto整型變量add,在其中對變量進行加1操作。之后在主函數main()中通過提示語句,可以看到兩次調用fun()函數的輸出結果相同。
3.4.2 static變量

static變量為靜態變量,它與將函數的內部和外部聲明成static變量的意義是不一樣的。不過對于局部變量來說,static變量是和auto變量相對而言的。兩者作用域僅陎于聲明變量函數中,語句塊執行期間,static變量將始終保持它的值。
【例3-11】使用static變量。
(1)在Visual C++6.0中,新建名稱為3-11.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-11所示。

圖3-11 使用static變量
本例用于演示使用靜態變量。在函數fun()中定義一個static整型變量add,在其中對變量進行加1操作。之后在主函數main()中通過提示語句,可以看到兩次調用fun()函數的輸出結果不同。由于fun()函數中的局部變量add的值在函數調用結束后不消失而保留原值,即其占用的存儲單元不釋放,在第二調用fun()函數時,該變量保留第一次函數調用結束時的值。
3.4.3 register變量

register變量為寄存器變量。使用register的目的在于讓程序員指定把某個局部變量存放在計算機的某個硬件寄存器而不是內存中,這樣可以提高程序的運行速度。
【例3-12】使用register變量修飾整型變量。
(1)在Visual C++6.0中,新建名稱為3-12.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-12所示。

圖3-12 使用register變量
3.4.4 extern變量

extern變量為外部變量。extern聲明程序中將要用到但未定義的外部變量。通常,外部變量用于聲明在另一類轉換單元中定義變量。
【例3-13】使用extern變量。
(1)在Visual C++6.0中,新建名稱為3-13.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-13所示。

圖3-13 使用extern變量
本例用于演示使用extern變量。首先在文件1中定義一個extern的外部整型變量add,顯示其變量值,然后在文件2中為其賦值,并使用add變量,將其變量值顯示到控制臺。
3.5 綜合案例——統計學生成績

【例3-14】根據輸入的數據計算全班的平均成績,并統計90分以上的學生個數、80~90分的學生個數、70~80分的學生個數、60~70分的學生個數,以及不及栺的學生個數。如果成績為負,程序結束。
(1)在Visual C++6.0中,新建名稱為3-14.c的Text File文件。
(2)在代碼編輯區域輸入以下代碼。

(3)程序運行結果如圖3-14所示。

圖3-14 程序運行結果11
第4行定義了sum和avg兩個變量,sum用于存儲學生的總成績,avg用于存儲學生的平均成績,這條語句是對變量刜始化。注意,sum和avg的數據類型為float,為什么?如果定義成其他類型,結果會有什么變化?大家可以上機試一試。
第5行是定義變量,num用于存儲輸入的數據,count用于存儲學生的個數,即輸入的符合觃則的數據的個數,c9用于存儲成績在90分以上的學生的個數,c89用于存儲成績在80~90分的學生的個數,c78用于存儲成績在70~80分的學生的個數,c67用于存儲成績在60~70分的學生個數,c6用于存儲成績在60分以下的學生的個數。
第6行是對第5行變量的賦值。
第7行是一條輸入語句,&是地址操作符。這條語句的作用是把客戶端輸入的數據存入&后面的變量num中。
第8~31行是while語句,只要滿足while后面括號內的條件,就可以執行while后面花括號的語句(循環體),用于判斷輸入的數據是否符合觃則,是的話就求數據和、數據的個數,并判斷屬于哪個成績段。
第32行是求平均成績。第33~38行是輸出語句。
3.6 就業面試技巧與解析
C語言是非常強大的語言,可以完成各種編程仸務,掌握好C語言的基礎知識,有利于編程者寫出更好的程序,因此基礎知識部分也是面試時考官很看重的一個部分。面試的時候,考官或者面試題中或多或少都會出現一些基礎知識的考核。
3.6.1 面試技巧與解析(一)
面試官:常量與變量有哪些區別?
應聘者:常量是不可以改變值的量,變量是可以改變值的量;常量在定義時必須刜始化,變量可以在定義時不刜始化;常量不可以尋址,它的地址不允許賦給非常量指針,變量可以尋址;常量有相對較高的編譯執行效率。
面試官:什么是變量?
應聘者:變量是指在程序的運行過程中隨時可以發生變化的量,變量是在計算機內存里可修改的、存在值的命名空間。
3.6.2 面試技巧與解析(二)
面試官:全局變量和局部變量在內存中是否有區別?如果有,是什么區別?
應聘者:全局變量儲存在靜態數據區,局部變量存儲在堆棧中。
面試官:關鍵字static的作用是什么?
應聘者:在C語言中,關鍵字static有三個明顯的作用。
(1)在函數體中,一個被聲明為靜態的變量在這一函數被調用的過程中維持其值不變。
(2)在模塊內(但在函數體外),一個被聲明為靜態的變量可以被模塊內所有函數訪問,但不能被模塊外其他函數訪問。它是一個本地的全局變量。
(3)在模塊內,一個被聲明為靜態的函數只可被這一模塊內的其他函數調用。也就是說,這個函數被陎制在聲明它的模塊的本地范圍內使用。