1.數組名
我們看一下下面兩個聲明:
int a;
int b[10];
我們把變量a稱為標量,因為它是個單一的值。我們把變量b稱為數組,因為它是一些值的集合。b[0]表示數組中的第一個數,b[1]表示數組中的第二個數,以此類推。
我們知道b[0]的類型是整形,那麼,b的類型是什麼呢?它所表示的是什麼呢?一個合乎邏輯的答案似乎是它表示整個數組,但事實並非如此。在C語言中,數組名永遠代表一個指針常量,也就是數組第一個元素的地址,即 &b[0]。它的類型取決於數組的類型。
注意,這裡說的是“指針常量”,而不是上一篇文章說的“指針變量”。指針常量即不能改變指針所指向的值。即這樣的代碼是錯誤的:
int number = 0;
int a[10] = {0};
a = &number;
a雖然是一個整形指針,但是他是一個指針常量,不能將其值改變。
請不要根據數組名是指針這個事實得出指針和數組是相同的結論。數組具有一些和指針完全不同的特性。例如,數組具有確定的數量值,而指針只是一個標量值。
2.下標引用
在前面的聲明的上下文環境中,下面這個表達式是什麼意思呢?
*(b + 3);
首先,b的值是一個指向整形的指針常量。所以3這個值根據整形值得長度進行調整。加法運算的結果是另一個指向整形的指針,即 &b[3]。再通過*號對其解引用操作,相當於
*(&b[3])或者直接表示為b[3].
我們姑且可以這樣認為:除了優先級順序不同外,下標引用和指針間接訪問完全相同。例如,下面這兩個表達式是等同的:
array[subsricpt]
*(array + (subsript) )
讓我們看一個例子,鞏固復習一下剛才的知識
int array[10];
int *ap = array + 2;
在下面有關ap的表達式中,看看你能不能寫出對應的array表達式:
ap ,這個很容易,&array[2]或者*(array + 2)
*ap ,這個也很容易,相當於對ap進行解引用操作,相當於array[2]或者*(array+2)
ap[0],將其轉化成為*(ap + 0),即*ap,和上一個表達式等價。
ap+6,這個表達式相當於&array[2+6]或者*(array+2+6),即&array[8]或者
*(array+8)
*ap+6,小心,這裡有兩個操作符,不過間接訪問的優先級高於加法操作,所以該式等價於array[2]+6
ap[6],你也許會疑問?這是錯的嗎?的確,在別的語言裡他也許是錯的,但是在C語言裡他是正確的,我們說過,C語言中的下表操作與指針間接訪問操作完全相同,即
*(ap+6)
&ap,這個表達式是完全合法的,它表示ap指針的地址,即指針的指針。
好了如果上面的問題都難不倒你的話,拿來看看下面這個:
2[ap]
是的,你沒有看錯,2[ap],不是ap[2].
他的答案也許會令你大吃一驚:它是合法的。把它轉化成為對等的間接訪問表達式,你就會發現它的有效性:
*(2 + (array))
內層的括號是多余的,即他和*(array + 2)是等價的。
3.關於指針和數組的效率
在此筆者不想通過反匯編來實驗數組與指針的效率,讀者暫時可以這樣記住:
“假定這兩種方法都是正確的,下標絕不會比指針更有效率,但是指針有時會比下標更有效率”
摘自 Kernel & UI