1. 程式人生 > >(C/C++學習心得)6.陣列指標和指標陣列

(C/C++學習心得)6.陣列指標和指標陣列

說明:int (*p)[4] 和 int *p[4](陣列指標和指標陣列),如果你是一個初學者,也許當你看到這兩個名詞的時候,已經懵了。其實,只要你理解了其中的含義.這兩個名詞對你來說會相當簡單並且很有趣,下面,我們就來深入探討一下究竟什麼是陣列指標,什麼是指標陣列。

一.指標陣列

1.前面我們已經學過陣列了,比如說要建立一個一維整型陣列,該怎麼建立呢?應該是這樣的:int arr[N];其中,arr是陣列名,即變數名,N是你所建立的這個陣列中的元素個數,而前面的int則是這些元素的型別。所以其實可以將它讀作整型變數陣列。那萬一你所建立的陣列元素不是整型和浮點型這些基本型別,而是一個指標型別呢?這就是指標陣列了。

2.指標陣列,首先它也是一個數組,只不過這個陣列中的元素的型別為指標型別,舉個例子:double *arr[4],這是一個指標陣列,包含四個元素,其中每個元素都是double*型別的,簡單來說,它就是一個用來儲存指標的陣列。用一個圖來說明這個指標陣列的記憶體佈局:

捕獲

3.既然指標陣列是一個數組,那麼它就應該有陣列所應具有的一些特點。舉個例子,對於double* p[4],p+1加的是陣列的步長,即一個double*的大小,四個位元組(注意:在32位機中,所有指標的大小都為4個位元組)。而如果對陣列名p進行取地址後,則&p+1加的是sizeof(p),即4*4 = 16個位元組,即&p+1就跨過了整個陣列。

示例:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     double *p[4] = {NULL};
  5     printf("p  = %p\t",p);
  6     printf("p+1  = %p\n",p+1);
  7     printf("&p = %p\t",&p);
  8     printf("&p+1 = %p\n",&p+1);
  9     return 0;
 10 }

程式執行結果:

捕2獲

二.陣列指標

1.指標相信大家都比較熟悉了,比如:int *p定義了一個指標p,該指標指向一個整型資料單元,如果對該指標執行加1操作,則加的是4個位元組;又如char *q定義了一個指標q,該指標指向一個字元型的資料單元,如果對該指標執行加1操作,則實際上加的是1(個位元組)。那麼問題來了,萬一要定義一個指標,它所指向的資料單元為一個一維陣列怎麼辦呢?對他執行加1操作又能得到什麼呢?這就是陣列指標了。

2.陣列指標,首先得明白它是一個指標,只不過這個指標指向的資料單元為一個數組,舉個例子,現在有一個一維陣列int arr[4];現在要定義一個數組指標來指向它,按照一般指標的理解,應該是這樣的,int[4]* p;表示定義一個指標p,而該指標的型別為int[4]*型的,但這在編譯器中是會報錯的,沒什麼理由,語法規定。實際上對這個陣列指標的定義應該是這樣的:int (*p)[4] = arr;說實話,這樣看著,筆者覺得挺彆扭的,不過沒辦法,編譯器就只認這個寫法,不過這完全不影響我們按照第一種寫法去理解陣列指標的本質。

3.上面已經說了,陣列指標實質就是一個指標,只不過其指向的型別與基本型別不同罷了。對於基本型別的指標,執行加1加的是指標指向資料型別的位元組數,那麼對於陣列指標呢?顯然加1加的也是指標指向資料型別的位元組數,那麼陣列指標指向資料型別的大小怎麼判斷呢?舉個例子:int(*p)[4],下面將通過一張記憶體資料圖對此進行闡述:

捕3獲

如圖:該指標裡面存的是一個數組的首地址,只不過該指標的型別為int[4] *型,這就導致了該指標的步長為4*4 = 16個位元組,所以對該指標執行加一操作,實際上加的是16個位元組,即整個陣列的大小。

  1 #include<stdio.h>
  2 int main()
  3 {
  4     int arr[4];
  5     int (*p)[4] = (int(*)[4])arr;
  6     printf("%p\t",p);
  7     printf("%p\n",p+1);
  8     return 0;
  9 }

程式執行結果:

捕4獲

4.陣列指標與二維陣列的關係是什麼呢?首先要知道,二維陣列 int arr[m][n] 可以想象成是具有m行,n列的一個數組矩陣,也可以想象成是有m個一維陣列,其中每個一維數組裡面又有n個int型的元素.那麼是否可以用一個型別為int[n] *型的指標指向該二維陣列來實現行間跳轉訪問呢?答案是肯定的!就拿上面例子來說,假如有一個二維陣列int arr[m][n],則可以定義一個數組指標為:int (*p)[n] = arr(這裡最好強轉一下),然後用p對陣列進行訪問,由以上可講可知,這裡的p+1加的是n*4個位元組,即加的是二維陣列每行的位元組數。

示例:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     int arr[3][4];
  5     int (*p)[4] = (int(*)[4])arr;
  6     printf("%p\t",p);
  7     printf("%p\n",p+1);
  8     return 0;
  9 }
 10 

程式執行結果:

捕454獲

注意:二維陣列的儲存在記憶體中實際上是線性儲存的,可以說任何資料在記憶體上的儲存都是線性儲存的,但這並不影響我們用二維的思維去理解它。

三.下面是一個數組指標當做二維陣列名訪問陣列的示例,只是為了鞏固與拓展一下以上,對於二維陣列名的具體使用方式,在下次更新(後天)會詳細介紹。這裡就簡單介紹一下,當把二維陣列名賦給一個指標陣列後,例如如下示例,則該指標就擁有了二維陣列名訪問二維陣列的方式,比如在這裡,p代表陣列的首地址,由於其擁有了二維陣列名的特性,則**p就是二維數組裡的第一個元素,而*(*(p+i)+j)是二維陣列第i行第j列的元素。

示例:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     int arr[3][4];
  5     int count = 0;
  6     for(int i = 0;i<3;i++)
  7         for(int j = 0;j<4;j++)
  8             arr[i][j] = count++;
  9     for(int i = 0;i<3;i++)
 10     {
 11         for(int j = 0;j<4;j++)
 12             printf("%2d  ",arr[i][j]);
 13         putchar(10);
 14     }
 15     int (*p)[4] = (int(*)[4])arr;
 16     for(int i = 0;i<3;i++)
 17     {
 18         for(int j = 0;j<4;j++)
 19             printf("%2d  ",*(*(p+i)+j));
 20         putchar(10);
 21     }
 22     return 0;
 23 }

程式執行結果:

656獲