“數組和指針是相同的”是一種非常危險、並不完全正確的說法。
ANSI標准:
*x;
y[];
數組定義不等同於
指針的外部聲明的情況:
文件1:
mango [];
文件2:
* mango;
上述代碼的錯誤如下:
C語言中的“對象”(不同於C++或其他面向對象編程語言的‘對象’,這裡的對象只是跟
鏈接器有關的“東西”,如函數和變量)必須
有且只有一個定義,但它可以有多個extern聲明。
定義:創建了一個對象,確定對象的類型並分配內存。只能出現在一個地方。
聲明:描述了一個對象,說明了在其他地方創建(定義)的對象的名字,允許在後面的代碼中使用。可以多次出現。
聲明乃普通的聲明,描述其他地方創建的對象;而定義則相當於特殊的聲明,它為對象分配內存。
“地址y”和“地址y的內容”之間的區別:
在賦值語句“X = Y;”中:
X是左值,是一個
地址,表示存儲結果的地方,在編譯時可知;
Y是右值,含義是
Y所代表的地址的內容,運行時可知。
標准規定賦值符必須用可修改的左值作為它左邊一側的操作數。
每個符號的地址在
編譯時可知。而對於指針,必須首先在
運行時取得它的當前值,然後才能進行解除引用操作。
如下代碼:
a[] = ;
數組a的地址為0x002afd8c,這個地址也存儲了字符“a”——
直接引用。
而對於指針來說:
* p = ;
指針p的地址為0x003cf808,這個地址裡面“裝”的內容還是一個四字節的地址0x012d5858,這個地址裡面才“裝”的是字符a——
間接引用。
綜上所述:當把p“定義為指針,但以數組方式引用時”,p[i]產生的效果是
編譯器會直接將p的地址加上偏移量(i * 步長)然後得到存儲在該內存地址的內容。但正確的做法應該是
取得存儲於p地址處的內容,將其作為基地址(字節數取決於機器的位數)再與偏移量相加,產生一個地址,訪問這個地址得到內容。
指針變量本身始終位於同一個地址(編譯時可知),但其內容在任何時候都可以不相同(可以指向不同的變量,這些變量可以有不同的值)。
相對的,數組的地址並不能改變,在不同的時候它的內容可以不同。
數組和指針都可以在它們的定義中用字符串常量進行初始化,但其
底層的機制卻不相同。
定義指針時,編譯器
只是分配指針本身的空間,除非在定義時用字符串常量進行初始化。在ANSI C中,初始化指針所創建的字符串常量被定義為只讀。試圖通過指針修改這個字符串的值會出現
未定義的行為。
而由字符串初始化的數組是可以修改的。