C語言多維陣列與多級指標

來源:互聯網
上載者:User
多維陣列與多級指標也是初學者感覺迷糊的一個地方。超過二維的數組和超過二級的指標其實並不多用。如果能弄明白二維數組與二級指標,那二維以上的也不是什麼問題了。所以本節重點討論二維數組與二級指標。
一、二維數組 1、假想中的二維數組布局
我們前面討論過,數組裡面可以存任何資料,除了函數。下面就詳細討論討論數組裡面存數組的情況。Excel 表,我相信大家都見過。我們平時就可以把二維數組假想成一個excel表,比如:
   char a[3][4];
2、記憶體與尺子的對比
實際上記憶體不是表狀的,而是線性。見過尺子吧。尺子和我們的記憶體非常相似。一般尺子上最小刻度為毫米,而記憶體的最小單位為1 個byte。平時我們說32 毫米,是指以零開始位移32 毫米;平時我們說記憶體位址為0x0000FF00 也是指從記憶體零地址開始位移0x0000FF00 個byte。既然記憶體是線性,那二維數組在記憶體裡面肯定也是線性儲存的。實際上其記憶體布局如下圖:
以數組下標的方式來訪問其中的某個元素:a[i][j]。編譯器總是將二維數組看成是一個一維數組,而一維數組的每一個元素又都是一個數組。a[3]這個一維數組的三個元素分別為:
a[0],a[1],a[2]。每個元素的大小為sizeof(a[0]),即sizof(char)*4。由此可以計算出a[0],a[1],a[2]三個元素的首地址分別為& a[0],& a[0]+ 1*sizof(char)*4,& a[0]+ 2*sizof(char)*4。亦即a[i]的首地址為& a[0]+ i*sizof(char)*4。這時候再考慮a[i]裡面的內容。就本例而言,a[i]內有4個char 類型的元素,其每個元素的首地址分別為&a[i],&a[i]+1*sizof(char),&a[i]+2*sizof(char)&a[i]+3*sizof(char),即a[i][j]的首地址為&a[i]+j*sizof(char)。再把&a[i]的值用a 表示,得到a[i][j]元素的首地址為:a+ i*sizof(char)*4+ j*sizof(char)。同樣,可以換算成以指標的形式表示:*(*(a+i)+j)。

經過上面的講解,相信你已經掌握了二維數組在記憶體裡面的布局了。下面就看一個題:
#include <stdio.h>
intmain(int argc,char * argv[])
{
   int a [3][2]={(0,1),(2,3),(4,5)};
   int *p;
   p=a [0];
   printf("%d",p[0]);
}
問列印出來的結果是多少。

很多人都覺得這太簡單了,很快就能把答案告訴我:0。不過很可惜,錯了。答案應該是1。如果你也認為是0,那你實在應該好好看看這個題。花括弧裡面嵌套的是小括弧,而不是花括弧。這裡是花括弧裡面嵌套了逗號運算式。其實這個賦值就相當於
   int a [3][2]={ 1, 3,5};
所以,在初始化二維數組的時候一定要注意,別不小心把應該用的花括弧寫成小括弧
了。

3、&p[4][2] - &a[4][2]的值為多少。
上面的問題似乎還比較好理解,下面再看一個例子:
   int a[5][5];
   int (*p)[4];
   p = a;
問&p[4][2] - &a[4][2]的值為多少。

這個問題似乎非常簡單,但是幾乎沒有人答對了。我們可以先寫代碼測試一下其值,然後分析一下到底是為什麼。在Visual C++6.0 裡,測試代碼如下:
intmain()
{
   int a[5][5];
   int (*p)[4];
   p = a;
   printf("a_ptr=%#p,p_ptr=%#p\n",&a[4][2],&p[4][2]);
   printf("%p,%d\n",&p[4][2] - &a[4][2],&p[4][2] - &a[4][2]);
   return 0;
}
經過測試,可知&p[4][2] - &a[4][2]的值為-4。這到底是為什麼呢。下面我們就來分析一下:前面我們講過,當數組名a 作為右值時,代表的是數組首元素的首地址。這裡的a 為二維數組,我們把數組a 看作是包含5 個int 類型元素的一維數組,裡面再儲存了一個一維數組。

如此,則a 在這裡代表的是a[0]的首地址。a+1 表示的是一維數組a 的第二個元素。a[4]表示的是一維數組a 的第5 個元素,而這個元素裡又存了一個一維數組。所以&a[4][2]表示的是&a[0][0]+4*5*sizeof(int) + 2*sizeof(int)。

根據定義,p 是指向一個包含4 個元素的數組的指標。也就是說p+1 表示的是指標p 向後移動了一個“包含4 個int 類型元素的數組”。這裡1 的單位是p 所指向的空間,即4*sizeof(int)。所以,p[4]相對於p[0]來說是向後移動了4 個“包含4 個int 類型元素的數組”,即&p[4]表示的是&p[0]+4*4*sizeof(int)。由於p 被初始化為&a[0],那麼&p[4][2]表示的是&a[0][0]+4*4*sizeof(int)+2* sizeof(int)。

再由上面的講述,&p[4][2] 和&a[4][2]的值相差4 個int 類型的元素。現在,上面測試出來的結果也可以理解了吧。其實我們最簡單的辦法就是畫記憶體布局圖:
這裡最重要的一點就是明白數組指標p 所指向的記憶體到底是什麼。解決這類問題的最好辦法就是畫記憶體布局圖。
二、二級指標 1、二級指標的記憶體布局
二級指標是經常用到的,尤其與二維數組在一起的時候更是令人迷糊。例如:
   char **p;
定義了一個二級指標變數p。p 是一個指標變數,毫無疑問在32 位系統下佔4 個byte。

它與一級指標不同的是,一級指標儲存的是資料的地址,二級指標儲存的是一級指標的地址。下圖協助理解: 我們試著給變數p 初始化:
A)
p = NULL;
B)
char *p2; p = &p2;
任何指標變數都可以被初始化為NULL(注意是NULL,不是NUL,更不是null),二級指標也不例外。也就是說把指標指向數組的零地址。聯想到前面我們把尺子比作記憶體,如果把記憶體初始化為NULL,就相當於把指標指向尺子上0 毫米處,這時候指標沒有任何記憶體可用。

當我們真正需要使用p 的時候,就必須把一個一級指標的地址儲存到p 中,所以B)的賦值方式也是正確的。

給p 賦值沒有問題,但怎麼使用p 呢。這就需要我們前面多次提到的鑰匙(“*”)。
第一步:根據p 這個變數,取出它裡面存的地址。
第二步:找到這個地址所在的記憶體。
第三步:用鑰匙開啟這塊記憶體,取出它裡面的地址,*p 的值。
第四步:找到第二次取出的這個地址。
第五步:用鑰匙開啟這塊記憶體,取出它裡面的內容,這就是我們真正的資料,**p 的值。

我們在這裡用了兩次鑰匙(“*”)才最終取出了真正的資料。也就是說要取出二級指標所真正指向的資料,需要使用兩次兩次鑰匙(“*”)。

至於超過二維的數組和超過二維的指標一般使用比較少,而且按照上面的分析方法同樣也可以很輕鬆的分析明白,這裡就不再詳細討論。讀者有興趣的話,可以研究研究。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.