(重慶三峽學院計算機科學與工程學院 重慶 404100)
C語言指針數據類型是整個C語言教學的重點難點。指針這個詞是從英文單詞 “pointer”直譯而來,事實上,指針更應該翻譯為地址,指針變量稱之為地址變量更合適。由于指針數據類型的存在,使得C語言可以直接同計算機內存打交道,這是C語言的低級語言特征。但是,由于指針變量的特殊性,使得C語言初學者在學習的時候往往感到很困惑,不知道何時取的是地址,何時取的是值。下面以一維數組和二維數組與指針變量的示例來理解指針變量的用法。
先來看指針和一維數組的關系,程序主要代碼如下:
1:int arr[5]={1,2,3,4,5};
2:int *p;
3:p=arr;
4:printf(“%x %x %x ”,p,arr,&arr[0]);
5:printf(“%d %d %d %d ”,*p,*arr,arr[0],p[0]);

以上程序定義了一維整型數組arr和指向此一維數組的整型指針變量p。在定義時,符號*表示定義的是一個指針變量,符號[ ]表示定義的是一個數組。除了定義外,符號*和[ ]均具有“解地址”的功能,和另一個取地址符號“&”具有相反的功能,就像除法是乘法的逆運算一樣。程序第4行運行后均輸出十六進制的地址,p是指針變量,由于程序第3行的賦值語句,p和arr均表示地址,但p是地址變量,值可變,arr為地址常量,值不能變,即p++,++p,p- -,- -p均是可行的,但arr自增自減不行。由于p賦值為arr數組名,即p此時表示arr數組首地址,也是arr數組第0個元素的地址,所以p,arr,&arr[0]地址相同。程序第5行運行后均輸出的是arr數組第0個元素的值。由第4行全為地址如何變成第5行的全為值呢?有兩種方式,一種用“解地址”符號*,例如*p,*arr;另一種用“解地址”符號[ ],例如p[0],arr[0]。類似地,要表示arr數組第1個元素的地址,可以表示為p+1,arr+1,&arr[1]。要表示arr數組第1個元素的值,可以表示為*(p+1),*(arr+1),arr[1],p[1]。此時,p和arr可以互換。那&p表示什么呢?指針變量是一種特殊的變量,變量中存的是其它變量的地址值,但是指針變量本身也是要占內存空間的,所以&p表示的是指針變量p本身的地址,一般占4個字節或8個字節,這取決于編譯器,例如VC++6.0給指針變量分配4個字節的空間,而DevC++給指針變量分配8個字節的空間。
接下來看指針和二維數組的關系,程序主要代碼如下:
1:int a[3][4]={1,2,3,4,10,20,30,40,100,200,300,400};
2:int(*p)[4];
3:p=a;
4:printf("%x %x %x %d %x %x %d %d ",a,*a,*a+1,**a,a+1,*(a+1),**(a+1),*(*(a+1)+2));
5:printf("%x %x %x %d %x %x %d %d ",p,*p,*p+1,**p,p+1,*(p+1),**(p+1),*(*(p+1)+2));
6:printf("%x %x %x ",a[2],&a[2],&a[2][0]);
7:printf("%x %x %x ",p[2],&p[2],&p[2][0]);
8:printf("%d %d %d ",a[2][1],*(a[2]+1),*(*(a+2)+1));
9:printf("%d %d %d ",p[2][1],*(p[2]+1),*(*(p+2)+1));

以上程序定義了一個3行4列的二維整型數組a和指向此二維數組的整型指針變量p,如第2行這樣定義的指針變量相當于行指針,可以用來遍歷二維數組a的行,它與指向一維數組的指針變量不同之處在于,若指針變量p指向一維數組,則p+1表示一維數組下一個元素的地址,若指針變量p指向二維數組,則p+1表示二維數組下一行的首地址。當然,若指針變量p不是第2行這么定義的,而是直接定義為int *p;p=a;這種情況下p+1表示下一個元素的地址。由第4行可以知道,a、*a輸出的都是一樣的地址值,但含義是不同的,a表示的是整個數組的首地址和第0行的首地址,但*a表示的是第0行第0列元素的地址。符號*具有“解地址”的功能,但由于是二維數組,解一次地址并不能取到某個元素的值,如果再解一次地址,例如**a就表示第0行第0列元素的值。由于是二維數組,a+1和p+1一樣都表示數組第1行的首地址。*(a+1)解一次地址,表示第1行第0列元素的地址,如果再解一次地址,則**(a+1)表示第1行第0列元素的值。*(a+1)+2表示行指針先定位到第1行第0列,表示地址,列指針再移動2個元素的位置,即表示定位到第1行第2列,仍然為地址。如果再用一次*號,則表示對應的元素的值了。類似地,符號[ ]具有解地址的功能。例如第6行a[2]表示第2行第0個元素的地址(從0行開始),&a[2]表示對第2行取地址,即第2行首地址,&a[2][0]表示對a[2][0]這個元素取地址,3個地址都是一樣的,但含義不同。
由第8行可知,定義了二維數組和相應的行指針,要想取到數組元素的值,要么需要2個解地址符號*,要么需要1個*和1個[ ],要么需要2個[ ]。那么只有1個*或[ ]表示取到某個元素的地址,而1個*或[ ]都沒有,則表示某一行的首地址。而取地址符號“&”就像是“*”和“[ ]”相反效果的符號一樣。另外,由程序可知,指針變量名和數組名在很多情形下可以互相替換,效果一樣。
C語言的精華在于指針,而指針又是比較難學的,初學者最不容易理解的就是它的地址與值的關系。本文通過兩個指針變量使用示例,將指針變量與數組中元素的地址和值作了詳細的闡釋,相關概念能幫助初學者熟練使用指針變量進行數組元素遍歷。