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

2021-09-30 12:25:16 字數 3733 閱讀 5638

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

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

一、二維陣列一維化

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

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

[cpp]view plain

copy

print?

int iarr[2][3]=;  

int iarr[2][3]=;

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

[cpp]view plain

copy

print?

int* p = iarr[0];  

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

[cpp]view plain

copy

print?

printf("%d,",p[3]);  

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

printf("%d,",p[3]);

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

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

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

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

[cpp]view plain

copy

print?

int **pp = iarr;  

int **pp = iarr;
不出意外,會出現下面的編譯錯誤:

error c2440: 「初始化」: 無法從「int [2][3]」轉換為「int **」

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

[cpp]view plain

copy

print?

int (*parr)[3]  

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

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

[cpp]view plain

copy

print?

int (*parr)[3] = iarr;  

int (*parr)[3] = iarr;
下面,我要訪問第一行第二列的元素,我可以用下面的**來訪問

[html]view plain

copy

print?

*(*(parr+1) + 2)  

*(*(parr+1) + 2)
也可以用陣列名來訪問:

[cpp]view plain

copy

print?

*(*(iarr+1) + 2)  

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

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

三、作為函式引數

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

宣告了如下函式:

[cpp]view plain

copy

print?

void testfun(int *parr,int nlength)  

void testfun(int *parr,int nlength)
假設,我用陣列名和指向首個元素位址的指標作為傳遞引數,看看有什麼效果?

[cpp]view plain

copy

print?

testfun(iarr,6);//「testfun」: 不能將引數 1 從「int [2][3]」轉換為「int *」

testfun(&iarr[0][0],6);  

testfun(iarr,6);//「testfun」: 不能將引數 1 從「int [2][3]」轉換為「int *」

testfun(&iarr[0][0],6);

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

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

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

現在的宣告是:

[cpp]view plain

copy

print?

void testfun(void *parr,int nlength)  

void testfun(void *parr,int nlength)
還是這樣傳參,

[cpp]view plain

copy

print?

testfun(iarr,6);  

testfun(&iarr[0][0],6);  

testfun(iarr,6);

testfun(&iarr[0][0],6);

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

C C 中二維陣列的分配

在c c 中動態分配二維陣列可以先申請一維的指標陣列,然後該陣列中的每個指標再申請陣列,這樣就相當於二維陣列了,但是這種方法會導致每行可能不相鄰,從而訪問效率比較低。如何申請連續的二維陣列了?本文將分別三個方面講解 一 動態申請列大小固定的二維陣列 二 c語言中動態申請連續的二維陣列 三 c 語言中...

C語言中二維陣列和指標

a或 a 1 行位址 a i 行位址加列位址test 如下所示 include int main void 第一行位址 printf p,p,p,p n nums,nums 0 nums,nums 0 第二行位址 printf p,p,p,p n nums 1,nums 1 nums 1 nums ...

二維陣列和指標的關係

二維陣列和指標 要用指標處理二維陣列,首先要解決從儲存的角度對二維陣列的認識問題。我們知道,乙個二維陣列在計算機中儲存時,是按行儲存的,即先儲存第一行的元素,再儲存第二行的元素。當把每一行看作乙個整體,即作為乙個大的陣列元素時,原來的 二維陣列也就變成乙個一維陣列了。而每個大陣列元素對應原來 二維陣...