NO IMAGE

1、陣列指標(指向陣列的指標)

(1)陣列在記憶體中的表示

建立一個陣列就是在記憶體裡面開闢一塊連續的空間,比如int a[4];就是在記憶體裡面開闢了一個大小為4*sizeof(int)位元組的記憶體空間。二維陣列是特殊的一維陣列。

先來看一段程式碼:

[cpp] view
plain
 copy

  1. <strong><span style=”font-size:16px;”>void main()  
  2. {  
  3.     int a[2][2]={1,2,3,4};//這是一個2*2的二維陣列  
  4.     int (*p)[2];//陣列指標  
  5.     p=a;//令p指向陣列a  
  6. }</span></strong>  


注意到程式碼中這句話:int (*p)[2];這裡的p是一個陣列指標變數。

a中各個元素在記憶體中是這樣存放的:

 

(2)理解陣列名和陣列指標變數

OK,現在我們思考a,a[0],a[1],p,a 1,a[0] 1,p 1到底是什麼,思考3秒鐘:

分析:

a是一個陣列名,型別是指向一維陣列的指標,不是變數,a的值是指標常量,即不能有a 或者a=p這些操作。a指向這塊連續空間的首地址,值是&a[0][0]。

a[0]是一維陣列名,型別是指向整型的指標,值是&a[0][0],這個值是一個常量。

a[1]是一維陣列名,型別是指向整型的指標,值是&a[1][0],這個值是一個常量。

p是一個陣列指標變數,指向一維陣列的指標變數,值是&a[0][0]。可以執行p ;p=a等操作。

a 1表示指向下一行元素,也可以理解為指向下一個一維陣列。

*(a 1)是取出第一行的首地址。

a[0] 1是指向第0行第1個元素,也可以理解為指向一維陣列a[0]的第一個元素。

p 1同a 1

*(p 1)同*(a 1)

雖然a跟a[0]值是一樣,但型別不一樣,表示的意義不一樣。通過分析就不難理解為什麼*(*(a i) j)和a[i][j]等效了。

 

(3)指標是陣列的迭代器

[cpp] view
plain
 copy

  1. <span style=”font-size:16px;”>#include<stdio.h>  
  2. #define M 2  
  3. #define N 3  
  4.   
  5. int main()  
  6. {  
  7.     int a[M][N]={1,2,3,4,5,6};  
  8.     int *start=&a[0][0];  
  9.     int * const end=start M*N;  
  10.     for(;start!=end;start )  
  11.         printf(“%-5d”,*start);  
  12.     putchar(‘\n’);  
  13.     return 0;  
  14. }</span>  


理解這段程式碼,用指標遍歷一個二維陣列,是不是很像C 標準庫裡面vector的迭代器。注意這裡只用了一個for迴圈,這也可以說明二維陣列其實就是特殊的一維陣列。

 

(4)陣列名與陣列指標變數的區別

 

從(2)中的分析中得出陣列名是指標,型別是指向元素型別的指標,但值是指標常量,宣告陣列時編譯器會為宣告所指定的元素數量保留記憶體空間。陣列指標是指向陣列的指標,宣告指標變數時編譯器只為指標本身保留記憶體空間。

 

看看這個程式碼:

[cpp] view
plain
 copy

  1. <strong><span style=”font-size:16px;”>#include<stdio.h>  
  2. void main()  
  3. {  
  4.     int a[2][2]={1,2,3,4};//這是一個2*2的二維陣列  
  5.     int (*p)[2];//陣列指標  
  6.     p=a;//令p指向陣列a  
  7.     printf(“%d\n%d\n”,sizeof a,sizeof p);  
  8. }</span></strong>  

猜一猜輸出是什麼?


困惑了嗎?為什麼結果會是這樣的呢,讓我們先初步瞭解一下sizeof關鍵字吧,下面是MSDN上sizeof的說明:

 

注意到說明中的紅色字型,當sizeof用於變數時返回這個變數佔用的實際空間的大小。當sizeof用於陣列名時,返回整個陣列的大小(這裡的大小指佔用的位元組數)。p是一個指標變數,這個變數佔用四個位元組。而a是陣列名,所以sizeof a返回陣列a中的全部元素佔用的位元組數。

 瞭解了sizeof,猜猜下面這段程式碼輸出什麼

[cpp] view
plain
 copy

  1. <span style=”font-size:16px;”><strong>#include<stdio.h>  
  2.   
  3. void main()  
  4. {  
  5.     int a[2][2]={1,2,3,4};//這是一個2*2的二維陣列  
  6.     int (*p)[2];//陣列指標  
  7.     p=a;//令p指向陣列a  
  8.     printf(“%d\n%d\n”,sizeof(a 1),sizeof(p 1));  
  9.     printf(“%d\n%d\n”,sizeof(a 0),sizeof(p 0));  
  10. }</strong></span>  


執行結果:

從結果中看出,a在做 運算時是轉化成了指標變數,此時a i的型別是一個指標變數,而不是一個陣列名。但a[i]是一個一維陣列的陣列名,sizeof(a[0])的值是8

 

現在再來看一段程式碼:

[cpp] view
plain
 copy

  1. <strong><span style=”font-size:16px;”>#include<stdio.h>  
  2.   
  3. void f(int a[][2])  
  4. {  
  5.     printf(“%d\n”,sizeof a);  
  6. }  
  7. void main()  
  8. {  
  9.     int a[2][2]={1,2,3,4};//這是一個2*2的二維陣列  
  10.     printf(“%d\n”,sizeof a);  
  11.     f(a);  
  12. }</span></strong>  

再猜一下輸出是什麼?

是不是又有點困惑呢?

解釋:這是因為傳參的時候陣列名轉化成指標變數,注意到函式f中f(int a[][2])這裡並不需要指定二維陣列的長度,此處可以改為int (*a)[2]。所以傳過來的就是一個陣列指標變數。這樣明白了吧!

 

總結:陣列名的型別是指向元素型別的指標,值是指標常量。(a 1)的型別是一個指標變數。把陣列名作為引數傳遞的時候實際上傳遞的是一個指標變數。sizeof對變數和陣列名操作時返回的結果會不一樣。陣列指標是指向陣列的指標,其值可以是變數。

2、指標陣列(存放指標的陣列)

(1)認識指標陣列

一個存放int型別的陣列稱為整型陣列,那麼存放指標的陣列就叫指標陣列。

[cpp] view
plain
 copy

  1. <strong><span style=”font-size:16px;”>#include<stdio.h>  
  2.   
  3. void main()  
  4. {  
  5.     int i=1,j=2;  
  6.     //p先跟[]結合,然後再跟*結合  
  7.     int *p[2];//指標陣列,存放指標的陣列  
  8.     p[0]=&i;  
  9.     p[1]=&j;  
  10.     printf(“%d”,sizeof(p));  
  11. }</span></strong>  

 斷點除錯分析:

 

此例陣列p就兩個元素,p[0]是指向i的指標,p[1]是指向j的指標。這兩個指標都是int型指標,所以p是存放int型指標的陣列。sizeof(p)返回陣列佔用的總空間,所以程式輸出是8

 

(2)指標陣列用法舉例

來自《the c programming language》的一個例子,對字串進行排序,看了下面這個例子,相信你就體會到了指標陣列的好處了。