1. 程式人生 > >C/C++中二維陣列和指標關係分析

C/C++中二維陣列和指標關係分析

        在C/c++中,陣列和指標有著密切的關係,有很多地方說陣列就是指標式錯誤的一種說法。這兩者是不同的資料結構。其實,在C/c++中沒有所謂的二維陣列,書面表達就是陣列的陣列。我猜想是為了表述方便才叫它二維陣列。

       在本文中,我也就叫它二維陣列。在C/C++中,二維陣列是陣列的陣列。陣列的每一個元素是一個數組。說起來有點繞,大家都知道,一維陣列也和指標那關比較密切,在本文中不重點闡述,下面就來闡述二維陣列和指標之間到底存在著什麼樣的關係。

      一、二維陣列一維化

           其實我這裡也只是表述的方便才叫這麼一個題目,我們怎麼利用一個數組的訪問方式來訪問二維陣列呢?下面來看一個具體的例子。

           首先,定義一個二維陣列。

int iArr[2][3]={0,1,2,3,4,5};


我們可以用一個指向int型的指標變數來訪問這個陣列,下面的程式碼是將陣列一維化:

int* p = iArr[0];

上面的iArr[0]就是代表第一個陣列的首地址,由於二維陣列在記憶體中的儲存也是先行後列的方式,所以第二行也緊跟第一行之後,這樣就可以用p來訪問陣列的元素值了,訪問的方式有下標和指標方式。

	printf("%d,",p[3]);
	printf("%d\n",*(p+3));

最後輸出的結果都是3。講完了一維化之後,下面來繼續看二維陣列的函式名到底是什麼意思?

        二、關於二維陣列名的探索

      可能想當然的話,二維陣列不就是一個二級指標嗎?真是這樣嗎?下面用程式碼來驗證下:

	int **pp = iArr;

       不出意外,會出現下面的編譯錯誤:

      error C2440: “初始化”: 無法從“int [2][3]”轉換為“int **”

      其實二維陣列名是一個數組指標,那什麼是陣列指標?陣列指標是指向一個數組首地址的指標,它實際上也是一種指標型別,類似於函式指標。它宣告如下: 

	int (*pArr)[3]

      它說明pArr是一個數組指標,它指向的是一個數組元素為int型別並且陣列元素的個數為3的一個數組指標,奇怪,中間的怎麼還有一個括號是啥玩意?呵呵,這個括號還真是不可少的。少了它就變為另外一種型別了:指標陣列。指標陣列是陣列型別,代表陣列的每一個元素是指標型別,它宣告如下:int  *pArr[3]。

      既然二維陣列的陣列名是指向第一行陣列的首地址,我們也叫它行指標。那麼我們可以用這種陣列名或者指標來訪問二維陣列的元素。

int (*pArr)[3] = iArr;

下面,我要訪問第一行第二列的元素,我可以用下面的程式碼來訪問

	*(*(pArr+1) + 2)

也可以用陣列名來訪問:

*(*(iArr+1) + 2)

這種方式是不是一下很難看懂,為什麼兩個星號啊?下面就我的理解來作一下解釋。僅以pArr做說明

首先,pArr是一個指向陣列的指標,在這個指標上加減一個整數都是移動整行,而不是一個元素。比如說,pArr+1代表的現在指標已經指向第一行元素了,也就是實際中的第二行,而要取得指標所指的物件,就要用到解引用運算子*,所以*(pArr+1)就代表第一行陣列,是整個這一行元素就取到了,那現在要取這一行的第二個元素,只須將指標再移動兩個元素,即*(iArr+1) + 2,這樣就指向了這個元素的地址,再解引用取得元素的值即可。說的有點囉嗦,或許有錯誤,望高手別噴就是了。

        三、作為函式引數

       一維陣列名作為函式引數實際上是退化為指標,二維陣列作為函式引數又有什麼不同呢?下面舉個例子說明。

 聲明瞭如下函式:

void TestFun(int *pArr,int nlength)

假設,我用陣列名和指向首個元素地址的指標作為傳遞引數,看看有什麼效果?

TestFun(iArr,6);//“TestFun”: 不能將引數 1 從“int [2][3]”轉換為“int *”
TestFun(&iArr[0][0],6);

直接傳遞陣列名是編譯通不過的。因為陣列名是陣列指標,而函式的引數是int*,兩者的型別化完全不一樣,所以不能轉換。

而陣列首元素的地址顯然是int*型別,所以就能編譯通過。

假設,我現在把這個函式的宣告換一下,看看這兩種傳參的方法會出現什麼情況?

現在的宣告是:

void TestFun(void *pArr,int nlength)

還是這樣傳參,

	TestFun(iArr,6);
	TestFun(&iArr[0][0],6);

編譯一下,居然都能通過了。在這裡,第二種方式顯然是沒問題的,因為int*可以轉化為void*。而第一種方式怎麼就可以了呢?因為iArr是陣列指標,當然也可以轉換為void*啦。

四、後記

     天快黑了,要吃飯去了。本文就寫到這裡,文中有什麼不對的地方,可以指出來,大家一起討論。