天天看點

《C語言程式設計:問題與求解方法》——2.10節變量

本節書摘來自華章社群《c語言程式設計:問題與求解方法》一書中的第2章,第2.10節變量,作者:何 勤,更多章節内容可以通路雲栖社群“華章社群”公衆号檢視

2.10 變量

一些動态變化的量(比如車速、溫度、股票價格等)稱為變量,這些量在源程式中用常量無法表示。

用c語言進行程式設計,要使用資料區(資料值可變)而不是代碼區(資料值不允許變)的記憶體單元來存放資料,都必須向編譯程式提出申請。

在c語言源程式中,向編譯程式申請一個(或幾個)存放某種類型資料的、值的大小可以變化的記憶體單元稱為定義變量。

2.10.1 變量的定義

定義一個簡單變量的格式為:

類型名 變量名;

類型名要使用關鍵字(比如int、float、char等,參見2.7節),變量名必須使用辨別符。

通過這種方式,編譯程式為我們在記憶體中配置設定一個合适大小的記憶體單元,用來存放一個此類型的資料。

例如,在定義變量 int num; 之後, c編譯程式通常會為變量num在記憶體中配置設定位址連續的2個(或4個)位元組作為一個記憶體單元,用來存放變量num的資料,編譯程式通過這種方式,把一個變量num與一個可以存放int型資料的記憶體單元聯系了起來,參見圖2-1。

《C語言程式設計:問題與求解方法》——2.10節變量

延伸與拓展:編譯程式為變量配置設定記憶體單元的技術内幕

編譯程式通過掃描每個函數中的所有變量定義,建立起一張表,即變量名–記憶體單元位址對照表。接下來在掃描所有的語句時,編譯程式就可以通過查找這張對照表,将源程式語句中出現的變量名轉變為機器語言指令中的記憶體單元的位址,即指令中的操作數。

編譯程式通過把變量名映射為記憶體位址的方式,達到了為變量配置設定相應記憶體單元的目的(類似于導遊通過将遊客名對應為房間号,達到了為每個遊客配置設定一個房間的目的)。

定義多個簡單變量的格式為:

類型名 變量名清單;

例如:

int age , num ,sum ;

在變量名清單中的多個變量名之間,要用逗号隔開,最後要以分号結束。編譯程式會為每一個同類型的變量配置設定同樣位元組數的記憶體單元,用來存放各變量的值。

最好使用意義明确的辨別符來定義變量,比如對于兔子的隻數,使用辨別符rabbit_count作為變量名就比用辨別符n作變量名要好得多。

2.10.2 變量名和變量的值

由于變量的記憶體單元由編譯程式配置設定,是以,在源程式的語句中,可以通過書寫變量名來表示要“通路”(即存或取)變量所對應的記憶體單元中的資料了,這個資料稱為變量的值。

比如,語句 num + 2 表示把變量名num所對應的記憶體單元中的值取出來(簡稱為把變量num的值取出來)再加上2( num + 2 其實是表達式,細節參見2.14節)。而語句“num = 21 ;”表示要把數值21存入變量名num所對應的記憶體單元中(簡稱為把數值21存入變量num中,“num = 21;”其實是指派語句,細節參見2.16節)。

變量的值是“取之不盡”的。從記憶體單元取得一個變量的值,其實隻是從一個記憶體單元中複制了這個值而已,該變量的值(沒有發生任何變化)仍然可以再次取用;但是,變量的值又是“一存就變”的,隻要運作了一條與存數操作有關的語句,(在記憶體單元中的)變量的“舊值”就被變量的新值覆寫掉了,變量的“舊值”将不複存在。

延伸與拓展:機器語言程式與進階語言源程式的最大不同點

機器語言程式中的指令經常使用記憶體位址(作為操作數)來指明要存取哪個記憶體單元中的資料;而進階語言源程式中的語句使用變量名來指明要存取哪個記憶體單元中的資料。這是機器語言程式與進階語言源程式最重要的不同點之一。記憶體位址是長長的、難以記憶的二進制位串;而變量名則是程式員自己所起的好記和易懂的(但要符合辨別符規定的)名字。

通過這種方式,首先,使得源程式更為簡明而可讀性又好。其次,進階語言源程式所要加工的資料獲得了極為寶貴的記憶體絕對位置無關性。這使得源程式具有了良好的移植性,也為多道程式同時放入記憶體中創造了先決條件。

但使用進階語言程式設計也存在一些缺點,在源程式的語句(或表達式)中,究竟何處是取變量的值(變量值不變),何處是将一個值存到變量之中(變量值将改變),變得有些模糊不清。這給初學者閱讀和了解程式的運作帶來一定的困難。這個問題讀者要給予充分的注意,否則你就很可能讀不懂很多程式。

2.10.3 各種基本類型的變量定義

1)整型變量(int):在程式運作時,需要記憶體單元存放(數值可以變化的)可正可負的整數時,要用此類型來定義。c編譯器一般配置設定2個(16位系統)或4個位元組(32位系統)的記憶體空間給一個int型變量。

占用兩個位元組的int型變量的取值範圍在–32768~32767之間,這個範圍比較小。

2)單精度浮點型變量(float):在程式運作時,需要記憶體單元存放以實數形式(即有小數分量)出現的量(比如34.1、–678.34、0.368等),要用此類型來定義。

比如,“float x,y;”就定義了兩個單精度浮點型變量x和y。

一般c編譯器配置設定4個位元組的記憶體空間給一個float型變量。

單精度浮點型變量的精度是十進制的7位。也就是說,隻有數值中的高7位數字肯定是正确無誤的。

float型變量的優點是:取值範圍遠比int型變量大(大約正數是在1.17×10–38~3.4×1038之間,負數取值範圍與正數是關于原點對稱的)。float型變量的缺點是:運算速度不如int型變量快,所存入的資料通常也隻是一個近似值。

3)字元型變量:用類型關鍵字char來定義字元型變量。

在程式運作時,需要用記憶體單元存儲單個字元(通常是ascii字元時),要用此類型來定義。c編譯器配置設定1個位元組的記憶體空間給一個char類型的變量。比如,“char ch1,ch2;”定義了兩個字元變量ch1和ch2。

字元型變量屬于一種從表面上看來是非數值型的量—字元。但其實在計算機的記憶體中,它通常就是一個以ascii碼形式存儲的,占用一個位元組記憶體的二進制碼。在c語言中,把這個ascii碼當作一個小整數來對待。比如字元'a',實際上被編譯程式看成是占用一個位元組的整數97(但在有些進階語言比如pascal語言中,不能把字元量當成整型量來對待)。

在進階程式設計語言中,任何類型變量的值都有一定的限定範圍(這是由于存儲變量值的位元組數有限而造成的),程式運作時超出了變量允許的取值範圍稱為發生了溢出(關于溢出的讨論,請參見本書後面的讨論)。這是在程式設計時要注意避免和進行處理的。

變量允許的取值範圍與所配置設定到的位元組數有關,不同編譯器為同一種類型變量配置設定的位元組數很可能不一樣,c語言标準隻是規定了各種類型變量所占用記憶體的最少位元組數(參見後續内容)。

延伸與拓展:“變量類型”的技術内幕

對于不同類型的變量,編譯程式配置設定給變量的記憶體單元位元組數很可能不一樣,資料的外部形式、機内形式不一樣,運算時選用的運算指令類型不一樣(比如對于實型量加法,編譯程式選用浮點數加法指令;而對于整型量加法,則選擇整數加法指令),輸入輸出變量值的轉換工作不一樣,變量取值的允許範圍可能不一樣,允許進行的運算也不一樣;但上述所有這些不一樣,除了最後兩項需要程式設計者注意外,大多都不需要程式設計者來具體操心。這些原本極為瑣碎的基礎性的程式設計工作,隻要我們恰當地定義了變量的類型,并在程式語句中合理地使用變量,編譯程式(包括标準輸入輸出庫函數)基本上就可以為我們代勞了。

2.10.4 變量的初始化

變量的初始化就是存入一個初始資料到變量對應的記憶體單元中。

在c語言中,變量定義後,通常還要進行初始化,也就是事先要将一個資料存放在變量對應的記憶體單元中。有了一個有效的确定值,該變量才能在語句和表達式中用來參與運算或進行輸出。否則,變量所對應的記憶體單元中(以前運作别的程式遺留下)的無效資料(我們将其稱為垃圾資料),就會在程式語句的執行運算或輸出時被誤用,造成程式運作錯誤。

最簡單的初始化變量的方法是在定義變量時,在變量後面用一個等号“=”給予它一個初始值。初始值必須是常量(或常量表達式)。比如以下變量定義:

這三條變量定義的“變量記憶體取值示意圖”如圖2-2所示。

變量名 number sum ch1 ch2 area

變量的值 垃圾資料 100 'a' 垃圾資料 65.432

《C語言程式設計:問題與求解方法》——2.10節變量

可見,除了變量 number和ch2中的值是垃圾資料外,int型變量sum、char型變量ch1和float型變量area都得以初始化了。

初始化變量還有其他兩種方法,即使用scanf()輸入庫函數和指派語句(請參見2.12節和2.16節)。

繼續閱讀