指針類型中的指針變量還可進行自增自減運算,而指針不能。指針變量既可以是左值,也可以是右值,指針隻能是右值。由指針、指針變量與運算符構成指針類型表達式。下麵說的“&”作為單目運算符時與一個變量結合就構成指針表達式,如&a,&p等,而“*”作為單目運算符隻可與指針類型結合,構成指針類型指向的數據類型表達式,如有:
int *p,a,b;
p=&a;
b=*p;
*p=10;
*&a=20;
其中“b=*p;”的*p就是整型表達式,也是一個整型變量,&a是指針類型表達式,*&a是一個整形表達式,也是一個整形變量。
對於指向指針變量的指針變量,還要複雜些[3]。
6 “&”和“*”運算符
C語言中有“&:按位與運算符,是雙目運算符,結合性是由左到右”和“&:取地址運算符,是單目運算符,結合性是由右到左”,有“*:乘法運算符,是雙目運算符,結合性是由左到右”和“*:指針運算符,是單目運算符,結合性是由右到左(“*”在聲明指針變量時也用到了)”。
對於取地址運算符&隻能與一個變量結合構成指針類型表達式,如有變量name,則&name就得到變量name的指針。
對於指針運算符*,意義是“取其指向的內容”,這裏說“取其指向的內容”不是指存儲單元裏存放的值,而是表示指針變量指向的變量。在有的書中說“例如:&a為變量a的地址,*p為指針變量p所指向的存儲單元的內容(即p所指向的變量的值)[1]”,這種說法值得商榷。筆者認為用“*p代表指針變量p所指向的存儲單元(即p所指向的變量)”的說法比較合適,更直接說 *p是一個變量,因為*p可以是左值。如下代碼:
void main()
{int a,*p;
p=&a;
*p=10;
printf("%d,%d
",a,*p);
*&a=20;}
輸出a和*p的結果都為10,說明*p與a等價。通過 *&a= 20;語句還可以改變a的值,也說明 *&a與a等價,*&a可以是左值[4]。
7數組的指針
C語言中的數組是一種線性構造型數據類型,特點是:
(1) 數組中數據元素是有序的。
(2) 數組中每一個元素都是具有相同數據類型的擁有不同下標的同名變量,每個元素用下標來訪問。
(3) 數組在內存中按下標遞增的次序在地址連續的一片內存區域中存放,最低的地址對應於第一個數組元素,最高的地址對應最後一個元素,程序運行中數組大小不可改變。
(4) 二維數組或多維數組可看成多重一維數組的結合。如二維數組可看成兩個相結合的一維數組,即一維數組中的每個元素又是一個一維數組的數組名。
數組名表示數組的入口指針,每個數組元素的指針由取地址運算符&與每個元素構成指針表達式得到。
二維數組可看成由若幹行,每行又由若幹列元素組成的有序元素的集合。二維數組名表示數組的入口,指向第一行一整行,叫行指針,數組元素的指針指向每一個元素,叫列指針。其實一維數組名就是列指針,指向第一個元素,這也是一維數組與二維數組一個很重要的區別。行指針和列指針可以互相轉換,用“&、*”兩個運算符可以達到轉換的目的。“&”把列指針轉成行指針,“*”把行指針轉成列指針,這種轉換不改變指針值的大小,改變了指針變量的指向。例如有int a[N][M];聲明一個 N行M列的二維數組。a 是數組的入口指針,是行指針,a[0]、a[1]、a[2]是列指針,&a[0][0]是元素a[0][0]的指針,其中a、*a、&a[0]、a[0]、&a[0][0]的值相等,但a、&a[0]指向行,*a、a[0]、&a[0][0]指向列。a與&a[0]等價,a[0]與 &a[0][0]等價,*a與a[0]、&a[0][0]也等價。
對於二維數組的第i行有:a+i 與 &a[i]等價,*(a+i)與a[i]等價,但不能說a+i與a[i]等價,盡管它們的值相等,a+i是指向第i行的行指針,a[i]是指向第i行第0列元素的,即是指向a[i][0]的列指針。
二維數組中指向第i行第j列的指針可以是如下形式:&a[i][j]、a[i]+j和*(a+i)+j,對第i行第j列元素的存取可以用如下形式:a[i][j]、*(a[i]+j)和*(*(a+i)+j)。
a+i(i>=0)也相當於是指向第i行有M個元素的一維數組的指針。
a又相當一有N個指針元素的指針數組,a相當指向指針的指針,N個元素不是指針(下標)變量,而是指針[3-5]。
8用指針變量引用數組的元素
當指針變量指向數組時,可以用該指針變量引用數組的元素。
用指針變量引用一維數組的元素,既可以用指針法(這要用到“*”指針運算符),也可以用下標法(即把指針變量當成數組名),相對簡單。