數組指針 與指針數組

1、數組指針(指向數組的指針)

(1)數組在內存中的表示

創建一個數組就是在內存裏面開闢一塊連續的空間,比如int a[4];就是在內存裏面開闢了一個大小爲4*sizeof(int)字節的內存空間。二維數組是特殊的一維數組。

先來看一段代碼:

  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[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)指針是數組的迭代器

  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)中的分析中得出數組名是指針,類型是指向元素類型的指針,但值是指針常量,聲明數組時編譯器會爲聲明所指定的元素數量保留內存空間。數組指針是指向數組的指針,聲明指針變量時編譯器只爲指針本身保留內存空間。

 

看看這個代碼:

  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,猜猜下面這段代碼輸出什麼

  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

 

現在再來看一段代碼:

  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類型的數組稱爲整型數組,那麼存放指針的數組就叫指針數組。

  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》的一個例子,對字符串進行排序,看了下面這個例子,相信你就體會到了指針數組的好處了。

 

 

 3、深入思考

數組名a、a[0]、a[1],數組指針p到底在內存中是怎麼存儲的呢?存放在內存中的哪裏呢?是在代碼段嗎?求解惑!

 

 4、參考資料

《c和指針》 《the c programming language》 等










發佈了42 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章