數組指標和指標數組的區別

來源:互聯網
上載者:User

標籤:

part one:

這兩個名字不同當然所代表的意思也就不同。我剛開始看到這就嚇到了,主要是中文太博大精深了,整這樣的簡稱太專業了,把人都繞暈了。從英文解釋或中文全稱看就比較容易理解。

指標數組:array of pointers,即用於儲存指標的數組,也就是數組元素都是指標

數組指標:a pointer to an array,即指向數組的指標

還要注意的是他們用法的區別,下面舉例說明。

int* a[4]     指標數組     

                 表示:數組a中的元素都為int型指標    

                 元素表示:*a[i]   *(a[i])是一樣的,因為[]優先順序高於*

int (*a)[4]   數組指標     

                 表示:指向數組a的指標

                 元素表示:(*a)[i]  

注意:在實際應用中,對於指標數組,我們經常這樣使用:

12 typedef int* pInt;pInt a[4];

這跟上面指標數組定義所表達的意思是一樣的,只不過採取了類型變換。

代碼示範如下:

1234567891011121314151617181920 #include <iostream> using namespace std; int main(){int c[4]={1,2,3,4};int *a[4]; //指標數組int (*b)[4]; //數組指標b=&c;//將數組c中元素賦給數組afor(int i=0;i<4;i++){a[i]=&c[i];}//輸出看下結果cout<<*a[1]<<endl; //輸出2就對cout<<(*b)[2]<<endl; //輸出3就對return 0;}

注意:定義了數組指標,該指標指向這個數組的首地址,必須給指標指定一個地址,容易犯的錯得就是,不給b地址,直接用(*b)[i]=c[i]給數組b中元素賦值,這時數組指標不知道指向哪裡,調試時可能沒錯,但運行時肯定出現問題,使用指標時要注意這個問題。但為什麼a就不用給他地址呢,a的元素是指標,實際上for迴圈內已經給數組a中元素指定地址了。但若在for迴圈內寫*a[i]=c[i],這同樣會出問題。總之一句話,定義了指標一定要知道指標指向哪裡,不然要悲劇。

類似的還有指標函數和函數指標,遇到了再說吧。

出處:http://www.cnblogs.com/Romi/archive/2012/01/10/2317898.html

 

 

part two:

數組指標(也稱行指標)
定義 int (*p)[n];
()優先順序高,首先說明p是一個指標,指向一個整型的一維數組,這個一維數組的長度是n,也可以說是p的步長。也就是說執行p+1時,p要跨過n個整型資料的長度。

如要將二維數組賦給一指標,應這樣賦值:
int a[3][4];
int (*p)[4]; //該語句是定義一個數組指標,指向含4個元素的一維數組。
 p=a;        //將該二維數組的首地址賦給p,也就是a[0]或&a[0][0]
 p++;       //該語句執行過後,也就是p=p+1;p跨過行a[0][]指向了行a[1][]

所以數組指標也稱指向一維數組的指標,亦稱行指標。

指標數組
定義 int *p[n];
[]優先順序高,先與p結合成為一個數組,再由int*說明這是一個整型指標數組,它有n個指標類型的數組元素。這裡執行p+1時,則p指向下一個數組元素,這樣賦值是錯誤的:p=a;因為p是個不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它們分別是指標變數可以用來存放變數地址。但可以這樣 *p=a; 這裡*p表示指標數組第一個元素的值,a的首地址的值。
如要將二維數組賦給一指標數組:
int *p[3];
int a[3][4];
p++; //該語句表示p數組指向下一個數組元素。註:此數組每一個元素都是一個指標
for(i=0;i<3;i++)
p[i]=a[i]
這裡int *p[3] 表示一個一維數組記憶體放著三個指標變數,分別是p[0]、p[1]、p[2]
所以要分別賦值。

這樣兩者的區別就豁然開朗了,數組指標只是一個指標變數,似乎是C語言裡專門用來指向二維數組的,它佔有記憶體中一個指標的儲存空間。指標數組是多個指標變數,以數組形式存在記憶體當中,佔有多個指標的儲存空間。
還需要說明的一點就是,同時用來指向二維數組時,其引用和用數組名引用都是一樣的。
比如要表示數組中i行j列一個元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]

優先順序:()>[]>*

出處:http://www.cnblogs.com/hongcha717/archive/2010/10/24/1859780.html

=========================================================================一、指標數組和數組指標的記憶體布局初學者總是分不出指標數組與數組指標的區別。其實很好理解:
指標數組:首先它是一個數組,數組的元素都是指標,數組佔多少個位元組由數組本身的大小決定,每一個元素都是一個指標,在32 位系統下任何類型的指標永遠是佔4 個位元組。它是“儲存指標的數組”的簡稱。
數組指標:首先它是一個指標,它指向一個數組。在32 位系統下任何類型的指標永遠是佔4 個位元組,至於它指向的數組佔多少位元組,不知道,具體要看數組大小。它是“指向數組的指標”的簡稱。

下面到底哪個是數組指標,哪個是指標數組呢:
A)
int *p1[10];
B)
int (*p2)[10];
每次上課問這個問題,總有弄不清楚的。這裡需要明白一個符號之間的優先順序問題。

“[]”的優先順序比“*”要高。p1 先與“[]”結合,構成一個數組的定義,數組名為p1,int *修飾的是數組的內容,即數組的每個元素。那現在我們清楚,這是一個數組,其包含10 個指向int 類型資料的指標,即指標數組。至於p2 就更好理解了,在這裡“()”的優先順序比“[]”高,“*”號和p2 構成一個指標的定義,指標變數名為p2,int 修飾的是數組的內容,即數組的每個元素。數組在這裡並沒有名字,是個匿名數組。那現在我們清楚p2 是一個指標,它指向一個包含10 個int 類型資料的數組,即數組指標。我們可以藉助下面的圖加深理解:二、int (*)[10] p2-----也許應該這麼定義數組指標這裡有個有意思的話題值得探討一下:平時我們定義指標不都是在資料類型後面加上指標變數名嗎?這個指標p2 的定義怎麼不是按照這個文法來定義的呢?也許我們應該這樣來定義p2:
   int (*)[10] p2;
int (*)[10]是指標類型,p2 是指標變數。這樣看起來的確不錯,不過就是樣子有些彆扭。其實數組指標的原型確實就是這樣子的,只不過為了方便與好看把指標變數p2 前移了而已。你私下完全可以這麼理解這點。雖然編譯器不這麼想。^_^
三、再論a 和&a 之間的區別既然這樣,那問題就來了。前面我們講過a 和&a 之間的區別,現在再來看看下面的代碼:
int main()
{
   char a[5]={‘A‘,‘B‘,‘C‘,‘D‘};
   char (*p3)[5] = &a;
   char (*p4)[5] = a;
   return 0;
}
上面對p3 和p4 的使用,哪個正確呢?p3+1 的值會是什嗎?p4+1 的值又會是什嗎?毫無疑問,p3 和p4 都是數組指標,指向的是整個數組。&a 是整個數組的首地址,a是數組首元素的首地址,其值相同但意義不同。在C 語言裡,賦值符號“=”號兩邊的資料類型必須是相同的,如果不同需要顯示或隱式的類型轉換。p3 這個定義的“=”號兩邊的資料類型完全一致,而p4 這個定義的“=”號兩邊的資料類型就不一致了。左邊的類型是指向整個數組的指標,右邊的資料類型是指向單個字元的指標。在Visual C++6.0 上給出如下警告:
   warning C4047: ‘initializing‘ : ‘char (*)[5]‘ differs in levels of indirection from ‘char *‘。
還好,這裡雖然給出了警告,但由於&a 和a 的值一樣,而變數作為右值時編譯器只是取變數的值,所以運行並沒有什麼問題。不過我仍然警告你別這麼用。

既然現在清楚了p3 和p4 都是指向整個數組的,那p3+1 和p4+1 的值就很好理解了。

但是如果修改一下代碼,把數組大小改小點,會有什麼問題?p3+1 和p4+1 的值又是多少呢?
int main()
{
   char a[5]={‘A‘,‘B‘,‘C‘,‘D‘};
   char (*p3)[3] = &a;
   char (*p4)[3] = a;
   return 0;
}

甚至還可以把代碼再修改,把數組大小改大點:
int main()
{
   char a[5]={‘A‘,‘B‘,‘C‘,‘D‘};
   char (*p3)[10] = &a;
   char (*p4)[10] = a;
   return 0;
}
這個時候又會有什麼樣的問題?p3+1 和p4+1 的值又是多少?

上述幾個問題,希望讀者能仔細考慮考慮,並且上機測試看看結果。

測試結果:
(1).char (*p2)[5]=a;必須使用強制轉換,如:char (*p2)[5]=(char (*)[5])a;
(2).把數組大小改變,都會編譯不通過,提示:
error C2440: ‘initializing‘ : cannot convert from ‘char (*)[5]‘ to ‘char (*)[3]‘
error C2440: ‘initializing‘ : cannot convert from ‘char (*)[5]‘ to ‘char (*)[10]‘

(3).把以上程式測試代碼如下:
int main()
{
  char a[5]={‘a‘,‘b‘,‘c‘,‘d‘};
  char (*p1)[5]= &a;
  char (*p2)[5]=(char (*)[5])a;

  printf("a=%d\n",a);
  printf("a=%c\n",a[0]);
  printf("p1=%c\n",**p1);
  printf("p2=%c\n",**p2);
  printf("p1+1=%c\n",**(p1+1));
  printf("p2+1=%c\n",**(p2+1));

  return 0;
}

輸出:
a=1638208
a=a
p1=a
p2=a
p1+1=?
p2+1=?
Press any key to continue

結論:
根據指標類型及所指對象,表示指標大小,每次加1,表示增加指標類型大小的位元組.----後面還會有解釋說明.
四、地址的強制轉換先看下面這個例子:
struct Test
{
   int Num;
   char *pcName;
   short sDate;
   char cha[2];
   short sBa[4];
}*p;

假設p 的值為0x100000。如下表運算式的值分別為多少?
   p + 0x1 = 0x___ ?
   (unsigned long)p + 0x1 = 0x___?
   (unsigned int*)p + 0x1 = 0x___?
我相信會有很多人一開始沒看明白這個問題是什麼意思。其實我們再仔細看看,這個知識點似曾相識。一個指標變數與一個整數相加減,到底該怎麼解析呢?

還記得前面我們的運算式“a+1”與“&a+1”之間的區別嗎?其實這裡也一樣。指標變數與一個整數相加減並不是用指標變數裡的地址直接加減這個整數。這個整數的單位不是byte 而是元素的個數。所以:p + 0x1 的值為0x100000+sizof(Test)*0x1。至於此結構體的大小為20byte,前面的章節已經詳細講解過。所以p +0x1 的值為:0x100014。

(unsigned long)p + 0x1 的值呢?這裡涉及到強制轉換,將指標變數p 儲存的值強制轉換成無符號的長整型數。任何數值一旦被強制轉換,其類型就改變了。所以這個運算式其實就是一個無符號的長整型數加上另一個整數。所以其值為:0x100001。

(unsigned int*)p + 0x1 的值呢?這裡的p 被強制轉換成一個指向無符號整型的指標。所以其值為:0x100000+sizof(unsigned int)*0x1,等於0x100004。

上面這個問題似乎還沒啥技術含量,下面就來個有技術含量的:在x86 系統下,其值為多少?
intmain()
{
   int a[4]={1,2,3,4};
   int *ptr1=(int *)(&a+1);//指向a數組後面的記憶體單元,&a+1表示向後移16個儲存單元
   int *ptr2=(int *)((int)a+1);//表示a的儲存單元的地址增加一個位元組
   printf("%x,%x",ptr1[-1],*ptr2);//ptr1[-1]其實指向的是a數組的最後一個單元,*ptr1則表示a數組的地址後移一個位元組之後的4個連續儲存單元所儲存的值
   return 0;
}
這是我講課時一個學生問我的題,他在網上看到的,據說難倒了n 個人。我看題之後告訴他,這些人肯定不懂彙編,一個懂彙編的人,這種題實在是小case。下面就來分析分析這個問題:

根據上面的講解,&a+1 與a+1 的區別已經清楚。

ptr1:將&a+1 的值強制轉換成int*類型,賦值給int* 類型的變數ptr,ptr1 肯定指到數組a 的下一個int 類型資料了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往後退4 個byte。所以其值為0x4。
ptr2:按照上面的講解,(int)a+1 的值是元素a[0]的第二個位元組的地址。然後把這個地址強制轉換成int*類型的值賦給ptr2,也就是說*ptr2 的值應該為元素a[0]的第二個位元組開始的連續4 個byte 的內容。

其記憶體布局如:好,問題就來了,這連續4 個byte 裡到底存了什麼東西呢?也就是說元素a[0],a[1]裡面的值到底怎麼儲存的。這就涉及到系統的大小端模式了,如果懂彙編的話,這根本就不是問題。既然不知道當前系統是什麼模式,那就得想辦法測試。大小端模式與測試的方法在第一章講解union 關鍵字時已經詳細討論過了,請翻到彼處參看,這裡就不再詳述。我們可以用下面這個函數來測試當前系統的模式。
int checkSystem()
{
  union check
  {
      int i;
      char ch;
  } c;
  c.i = 1;
  return (c.ch ==1);//如果當前系統為大端模式這個函數返回0;如果為小端模式,函數返回1。
}

如果當前系統為大端模式這個函數返回0;如果為小端模式,函數返回1。也就是說如果此函數的傳回值為1 的話,*ptr2 的值為0x2000000。如果此函數的傳回值為0 的話,*ptr2 的值為0x100。

出處: http://see.xidian.edu.cn/cpp/html/476.html

數組指標和指標數組的區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.