第二章 數組名是一個指針常量嗎?

 

數組名是一個指針常量這種觀點來源於數組名在表達式計算中與指針的結果等效性。例以下面的代碼:express

int a[10], *p = a, *q;數組

q = a + 1;lua

q = p + 1;指針

在效果上看,a + 1與 p + 1是相同的,這很容易給人一種a就是p的假象,但,這僅僅是假象。鑑於指針常量包含了指針和常量兩類概念,咱們能夠把這個問題分開兩部分進行討論。code

1、數組名是指針嗎?對象

在《C與指針》一書中,做者用一個著名的例子闡述了數組名與指針的不一樣。在一個文件中定義:int a[10];而後在另外一個文件中聲明:extern int *a; 筆者不在這裏重複其中的原理,書中的做者試圖從底層操做上闡述數組名與指針的不一樣點,但筆者認爲這個例子存在一些不足,a在表達式中會轉換爲一個非對象的符號地址,而指針a倒是一個對象,用一個非對象去跟一個對象比較,有「偷跑」的嫌疑,這個例子只是說明了數組名的非對象性質,只能證實對象與非對象實體在底層操做上的不一樣,事實上,如上一章所述,指針也有非對象形態。筆者認爲,無須從底層的角度上花費那麼多脣舌,僅僅從字面上的語義就能夠推翻數組名是一個指針的觀點。編譯器

首先,在C/C++中,數組類型跟指針類型是兩種不一樣的派生類型,數組名跟指針是兩種不一樣類型的實體,把數組類型的實體說成「是」另外一個類型的實體,自己就是荒謬的;io

其次,a + 1在效果上之因此等同於p + 1,是由於a進行了數組到指針的隱式轉換,這是一個轉換的過程,是converted to而不是is a的過程。若是是兩個相同的事物,又怎會有轉換的過程呢?當把a放在a + 1表達式中時,a已經從一個數組名轉換爲一個指針,a是做爲指針而不是數組名參與運算的;編譯

第三,a + 1與p + 1是等效關係,不是等價關係。等價是相同事物的不一樣表現形式,而等效是不一樣事物的相同效果。把數組名說成是指針實際上把等效關係誤解爲等價關係。class

所以,數組名不是指針,永遠也不是,但在必定條件下,數組名能夠轉換爲指針。

2、數組名是一個常量嗎?

看見這句話有人會以爲奇怪,數組定義以後就不能改變了,數組名不就是個常量嗎?在表達式中,數組名的確能夠轉換爲一個不變的符號地址,但在C中,不變的實體不必定是常量!並且,C/C++有常量與常量表達式之分,常量與常量表達式是兩種不一樣的實體,但常量表達式能夠做爲常量使用。C/C++中的常量雖然有所不一樣,但都不包括數組或數組名,並且數組名也不必定是常量表達式。

請在C90的編譯器中編譯以下代碼,注意不能是C99和C++的,由於C99和C++再也不規定數組的初始化器必須是常量表達式,會看不到效果:

int main( void )
{
    static int a[10], b[10];

    int c[10], d[10];

    int* e[] = { a, b };     /* A */

    int* f[] = { c, d };     /* B */

    return 0;

}

 

B爲何不能經過編譯?是因爲自動數組名並非常量表達式。在C中,常量表達式必須是編譯期的,只在運行期不變的實體不是常量表達式,請看標準的摘錄:

6.6 Constant expressions

A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be.

c和d是自動數組,首地址在編譯期是不可知的,由於這樣的對象在編譯期還不存在;a和b是靜態數組,靜態對象從程序開始時就已存在,所以a和b的首地址在編譯期是已知的,它們都屬於常量表達式中的地址常量表達式。

因此,C/C++中的數組名,都不是常量。C中的數組名,是否常量表達式要視其存儲連續性而定,全局數組、靜態數組名都是常量表達式,而自動數組名不是。在C++中,因爲再也不規定常量表達式必須是編譯期的,所以C++的數組名都是常量表達式。

相關文章
相關標籤/搜索