1. 程式人生 > >圖解陣列指標與多維陣列(附:為什麼指標加一,地址不一定加一)

圖解陣列指標與多維陣列(附:為什麼指標加一,地址不一定加一)

這裡不是單純討論什麼是陣列指標,什麼是指標陣列,而是在掌握了一些知識後再回頭看看陣列指標與陣列到底怎麼理解。(陣列指標:指向陣列的指標。指標陣列:指標構成的陣列)

 先放上一道題:


答案是10,20,30。

雖然是很常見的題,對於一個剛開始學C語言可能就可以做出來,但是你確定你真正的理解了麼?當你學的多的時候可能就會有其他疑問了。

比如我知道int(*p)[3]中的p是陣列指標,也就是p是一個指向長度為3的一個數組的指標。那麼我們看看這個指標都可以怎麼去用。

我們從基本的一維陣列去考慮,這樣p指向的只能是長度為3的陣列比如

int m[6]={1,2,3};//錯誤
int m[3]={1,2,3};
p=&m;
cout<<p[0][0]<<","<<p[0][1]<<","<<p[0][2]<<","//列印1,2,3
<<*(m+1)//列印2
<<*(p[0]+1)//列印2
<<*(p[1]+1)<<endl;//列印-858993460,這個數不同機器上,不同情況值是不同的
<<m<<","//列印002FFD04
<<&m[0]<<","//列印002FFD04
<<&m[0]+1<<","//列印002FFD08
<<&m[1]<<endl;//列印002FFD08


這裡的p[0][1]看起來可能有點奇怪,不過這恰恰能說明二維陣列到底是怎麼回事

p是一個指向陣列m的指標,那麼p[0]其實就是對p的一個解引用,也就是等價於*p,也等價於m

所以p[0][0]也就是m[0]。

這樣順理成章的我們來看看二維陣列

int n[][3]={10,20,30,40,50,60};
int (*p)[3];
p=n; 
cout<<p[0][0]<<","<<p[0][1]<<","<<p[1][0] //列印10,20,40
<<","<<*(p[1]+1) //列印50
<<","<<(*p)[2]<<","<<(*p+1)[2]<< //列印30,40
","<<p[0]<<","<<p[1]<<endl; //列印003AFEF0,003AFEFC
cout<<","<<(p+1)[0]<<","<<n[1]<< "," <<*n[1]<< endl; //列印003AFEFC, 003AFEFC,40

就如前面所說的,這次p是一個指向陣列n的指標,那麼p[0]其實就是對p的一個解引用,也就是等價於*p,也等價於*n,所以p[0][0]也就是n[0][0]。

你可能發現前面多次列印了地址,這個還能說明什麼呢?我們發現對指標地址進行加一後,我們的地址並不會直接加一,而是加了一箇中間包含資料所佔位元組數的大小。也就是說,如果指標指向一個int型資料(一般機器上int型都是4個位元組),那麼加一操作就會在地址上加4,比如上面的&m[0]與&m[0]+1。如果是指向char,加一操作就會在地址上加1。而如果對指向二維陣列頭的指標加一,那麼這個地址就會加上一行資料的總位元組數大小比如上面的p[0]與p[1]就分別等價於p與p+1。

看到這裡可能還會有疑惑?我讓int型的指標執行加一操作時地址也加一不可以麼?

我是這樣理解的,按照現在的計算機語言情況,最小的資料型別就是單字元,其長度為一個位元組。所以你的指標大小至少要能保證指向每一個位元組的內容,這樣才能保證所有的資料都可以被取到。所以指標可以在加一的同時地址也加一,也就是每個位元組對應一個地址。但是當你指向int型別的時候,你的加一操作也是讓地址加一的話,你指向的資料就變成了int型第二個位元組所組成的數,也就是說你無法獲取完整的int型別資料。

最後附上一張地址邏輯的示意圖,有助於大家理解。