3. 變數

變數(Variable)是編程語言最重要的概念之一,變數是計算機存儲器中的一塊命名的空間,可以在裡面存儲一個值(Value),存儲的值是可以隨時變的,比如這次存個字元'a'下次存個字元'b',正因為變數的值可以隨時變所以才叫變數。

常量有不同的類型,因此變數也有不同的類型,變數的類型也決定了它所占的存儲空間的大小。例如以下四個語句定義了四個變數fredbobjimmytom,它們的類型分別是字元型、整型、浮點型:

char fred;
int bob;
float jimmy;
double tom;

聲明和定義

C語言中的聲明(Declaration)有變數聲明、函數聲明和類型聲明三種。如果一個變數或函數的聲明要求編譯器為它分配存儲空間,那麼也可以稱為定義(Definition),因此定義是聲明的一種。在接下來幾章的示例代碼中變數聲明都是要分配存儲空間的,因而都是定義,等學到第 2 節 “定義和聲明”我們會看到哪些變數聲明不分配存儲空間因而不是定義。在下一章我們會看到函數的定義和聲明也是這樣區分的,分配存儲空間的函數聲明可以稱為函數定義。從第 7 章 結構體開始我們會看到類型聲明,聲明一個類型是不分配存儲空間的,但似乎叫“類型定義”聽起來也不錯,所以在本書中“類型定義”和“類型聲明”表示相同的含義。聲明和語句類似,也是以;號結尾的,但是在語法上聲明和語句是有區別的,語句只能出現在{}括號中,而聲明既可以出現在{}中也可以出現在所有{}之外。

浮點型有三種,float是單精度浮點型,double是雙精度浮點型,long double是精度更高的浮點型。它們之間的區別和轉換規則將在第 15 章 數據類型詳解詳細介紹,在隨後的幾章中我們只使用double類型,上一節介紹的常量3.14應該看作double類型的常量,printf%f也應該看作double型的轉換說明。給變數起名不能太隨意,上面四個變數的名字就不夠好,我們猜不出這些變數是用來存什麼的。而像下面這樣起名就很好:

char firstletter;
char lastletter;
int hour, minute;

我們可以猜得到這些變數是用來存什麼的,前兩個變數的取值範圍應該是'A'~'Z''a'~'z',變數hour的取值範圍應該是0~23,變數minute的取值範圍應該是0~59,所以應該給變數起有意義的名字。從這個例子中我們也看到兩個相同類型的變數(hourminute)可以一起聲明。

給變數起名有一定的限制,C語言規定必須以字母或下劃線_(Underscore)開頭,後面可以跟若干個字母、數字、下劃線,但不能有其它字元。例如這些是合法的變數名:Abc__abc___123。但這些是不合法的變數名:3abcab$。其實這個規則不僅適用於變數名,也適用於所有可以由程序員起名的語法元素,例如以後要講的函數名、宏定義、結構體成員名等,在C語言中這些統稱為標識符(Identifier)

另外要注意,表示類型的charintfloatdouble等雖然符合上述規則,但也不能用作標識符。在C語言中有些單詞有特殊意義,不允許用作標識符,這些單詞稱為關鍵字(Keyword)或保留字(Reserved Word)。通常用於編程的文本編輯器都會高亮顯示(Highlight)這些關鍵字,所以只要小心一點通常不會誤用作標識符。C99規定的關鍵字有:

auto  break  case  char  const  continue  default  do  double
else  enum  extern  float  for  goto  if  inline  int  long
register  restrict  return  short  signed  sizeof  static  struct  switch  typedef
union  unsigned  void  volatile  while  _Bool  _Complex  _Imaginary

還有一點要注意,一般來說應避免使用以下劃線開頭的標識符,以下劃線開頭的標識符只要不和C語言關鍵字衝突的都是合法的,但是往往被編譯器用作一些功能擴展,C標準庫也定義了很多以下劃線開頭的標識符,所以除非你對編譯器和C標準庫特別清楚,一般應避免使用這種標識符,以免造成命名衝突。

請記住:理解一個概念不是把定義背下來就行了,一定要理解它的外延和內涵,也就是什麼情況屬於這個概念,什麼情況不屬於這個概念,什麼情況雖然屬於這個概念但一般推薦的做法(Best Practice)是要儘量避免這種情況,這才算是真正理解了。