
學習C++數組的時候,對數組的了解不是很深。也不知道,為什么聲明一個數組,int a[10],為什么a就是數組的地址。
你可以這樣理解,將a理解為指向數組頭的一個指針,這樣就好理解了。理解了之后確實好像豁然開朗的樣子。這樣a[5]就等于*(a+5),也就相當于將數組頭指針向后推5個位置,然后取到該位置的數據了。仿佛一切都很完美。
可是當我對C++使用的越多的時候,就會發現這個理解越來越多紕漏。
我們知道,如果我們有一個int數組a[10],sizeof(a)會求出40。相信不少人都會寫過以下的代碼吧
int arraySize(int a[]) {
return sizeof(a)/sizeof(int);
}
我們想要求一個數組的長度,但是當我們用這個函數來求數組的長度的時候,會發現要么輸出1要么輸出2。為什么會這樣呢?
我們在C++面試的時候會遇到這樣的題目
int a[5] = {1,2,3,4,5};
int* p1 = (int*)(&a+1);
int* p2 = (int*)(a+1);
cout << *(p1-1) << " " << *(p2-1) << endl;
問輸出什么?
大家都知道輸出時5和1,那大家有沒有嘗試去理解一下為什么是這樣呢?
為了解決這個問題,我寫了一段代碼進行測試:
#include<iostream>
#include <typeinfo>
using namespace std;
#define type(a) typeid(a).name()
int main() {
int a[10] = {1,2,3,4,5,6,7,8,9,10};
cout << "a=" << a << " &a=" << &a << endl;
int* p1 = (int*)(&a+1);
int* p2 = (int*)(a+1);
cout << "*(p1-1)=" << *(p1-1) << " *(p2-1)=" << *(p2-1) << endl;
cout << "sizeof(a)=" << sizeof(a) << " sizeof(&a)=" << sizeof(&a) << endl;
cout << "TypeOf(a)=" << type(a) << " TypeOf(&a)=" << type(&a) << endl;
}
運行結果如下:
我們可以看到,一個數組a[10],a的值和&a輸出的值是一樣的。
但是對a+1和對&a+1卻會得到不同的結果。
對他們分別用sizeof函數取大小,發現a占用了40個字節,&a占用了8個字節。
最后我們查看a和&a的類別,發現a是A10_i類型的,而&a是PA10_i類型的。
這說明了什么?
說明了數組名a并不是一個int型的指針,而是一個新的數據類型,是一個A10_i類型,代表大小為10的int型的數組。而A10_i這個數據類型是會在內存中連續占用10個int型的空間,所以sizeof(a)會返回一個10*4的結果。而&a是一個PA10_i類型,就是指向A10_i數據類型的一個指針,一個指針的大小當然為8了。(根據系統的位數不同而不同)。
那為什么a和&a的輸出值相等呢?這是因為a是一個A10_i的數據類型,輸出的時候會把里面的數組的頭地址輸出出來。而&a時指向A10_i的一個指針,A10_i的地址就等同于他里面包含數組的頭地址,所以兩者會相等。
而&a+1與a+1得到的結果不相等,是因為a相當于一個指向int元素的指針,a+1會加上sizeof(int)的大小。而&a是一個指向A10_i的指針,&a+1會加上sizeof(A10_i)的大小,而sizeof(A10_i)=40,所以就可以解釋為什么兩者不同了。
至于為什么我們想寫一個函數來求數組的長度的時候會失敗,原因是我們的函數接收參數是一個真真正正的int型指針,在傳入參數時會進行類型轉換,將PA_i類型轉化為int型指針,對int指針進行sizeof當然求得指針本身的大小。只有對數組名這個數據類型進行sizeof求大小才能夠求得數組本身的大小。
說到底,就是數組名并不等同于一個指針。數組名是一個我們平常不能顯式聲明的數據類型,只不過里面包含了一個指針,指向數組的頭部。
如果你也想成為一名程序員那就關注我與我交流,不管是零基礎還是入門小白學習,要有個相互監督的伙伴!關注小編的專欄,手把手教你如何實現!工作需要、感興趣、為了入行、轉行需要學習C/C++的伙伴可以跟我學習,技術大牛助你早日成為一名優秀的程序員!
程序猿?zhuanlan.zhihu.com