深度解析數組名與指針的區別

最近經常遇到sizeof 運算符在計算數組大小出錯的問題,究其原因還是學藝不精,廢話不多說,上代碼。
首先看下面這段代碼:

#include<iostream>  
using namespace std;  
void fun1(int *P)  
{  
    cout<<"在函數1中"<<sizeof(P)<<endl;  
}  
void fun2(int P[])  
{  
    cout<<"在函數2中"<<sizeof(P)<<endl;  
}
int main()  
{  
    int A[10];  
    int* B=new int[10];  
    cout<<"數組名"<<sizeof(A)<<endl;  
    cout<<"指針"<<sizeof(B)<<endl;  
    fun1(A);  
    fun2(A);
}

結果輸出:
數組名40
指針4
在函數1中4
在函數2中4
這段代碼,可以很明確的看出幾個問題:
1.數組名和指針是有區別的
2.數組名在參數傳遞中會以指針形式傳遞

那麼爲什麼呢,我們可以查看sizeof 運算符的定義http://zh.cppreference.com/w/cpp/language/sizeof
這裏的解釋是:
sizeof解釋
1) 返回 類型 的對象表示的字節數。
2) 返回當 表達式 求值時所返回的類型的對象表示的字節數。
註解
依賴於計算機架構,字節可能具有八個或更多位,精確的位數記錄於 CHAR_BIT 中。
sizeof(char)、sizeof(signed char)、sizeof(unsigned char) 總是返回 1。

不能對函數類型、不完整類型或位域泛左值使用 sizeof。
當應用於引用類型時,其結果是被引用類型的大小。
當應用於類類型時,其結果是該類的對象的大小與這種對象放入數組時所需的額外填充的大小的總和。
當應用於空類時,總是返回 1。
當應用於某個表達式時,sizeof 並不對表達式進行求值,並且即便表達式所代表的是某個多態對象,其結果也是該表達式的靜態類型的大小。不進行左值向右值、數組向指針和函數向指針轉換。不過,其在形式上對純右值實參實施臨時對象的實體化: sizeof 確定其結果對象的大小。 (C++17 起)
由此,我們可以看出sizeof 運算符得出的值都是已分配好的固定長度,比如sizeof(結構體) 得出來的值,就是結構體的大小。

由此,我們就可以知道了,爲什麼sizeof(A) 與 sizeof(B)的結果不一樣了,因爲一個是數組名,一個是指針類型。
那麼,最關鍵的問題來了,爲什麼會出現這樣的差異,不是應該按照很多人說的,數組名 == 指針嗎。
我們看上面的例子fun1(A); 這個函數,很多人說,是數組名退化成指針,但是,我說這是扯犢子。
A++; 這個能成立嗎?
由此,數組名,可以看做一個指針常量,但是它又多了指針不具備的數組長度,個人看法是 類似於結構體名 或者就是一個特殊的結構體。
但是,這結束了嗎,NO!!!!!
我們看 fun2(A); 這個函數,又會有個困惑,不是數組名的傳遞嗎?
這裏我覺得是編譯器挖的坑。
前面不是已經說明了嗎,數組名是常量,但是常量在傳遞後就不是常量了,可以進行運算了,此時已經變成指針了。
不信的話,大家可以在void fun2(int P[]) 這個函數中,進行P++;
這個操作,在這裏是可以成立的!!!

再舉個例子

int main()  
{  
 foo(10);
}

void foo(int i)
{
 i++;
}

但是,常量變成變量,只是值的傳遞,其內涵和地址還是丟失了,於是fun2(A); 這個結果是正常的。
在深度解析一點sizeof就是,sizeof 只對具體對象的實例化後有效,例如:

struct test
{
int a,b,c,d,e,f,g,h;
};
int main()
{
test &r=*new test;
cout<<sizeof(test)<<endl;//32
cout<<sizeof(r)<<endl;//也是32
system("PAUSE");
}
r 引用的是整個的 test 對象而不是指向 test 的指針,所以 sizeof r 的結果和 sizeof test 完全相同。

雖然是個小問題,但是大家的共識與老師教的卻常常是反過來的。
最後,在下再次表達深深的希望,願我和我的同道中人能夠真正以謹慎的研究態度來認真思考開發中的問題,這樣才能在我們中間產生大師級的程序員,頂級的開發書籍。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章