鍍金池/ 教程/ C/ 數(shù)組與指針的糾葛
寫在前面的小測試
那些不安全的庫函數(shù)
數(shù)組與指針(一)
非局部跳轉(zhuǎn)
數(shù)組與指針的糾葛
輸出
類型轉(zhuǎn)換
函數(shù)指針
預處理

數(shù)組與指針的糾葛

數(shù)組與指針的糾葛

在C語言中,根據(jù)定義,表達式 e1[e2] 準確地對應于表達式 *((e1)+(e2))。因此,要求表達式 e1[e2] 的其中一個操作數(shù)是指針,另一個操作數(shù)是整數(shù)。且這兩個操作數(shù)的順序可以顛倒。

故: a[4] 等同于 4[a] 等同于 *(a+4)*
編譯器把所有的e1[e2]表達式轉(zhuǎn)換成 \
((e1)+(e2))。 所以,以下標的形式訪問在本質(zhì)上與以指針的形式訪問沒有區(qū)別,
只是寫法上不同罷了**!

多維數(shù)組

二維數(shù)組a[i][j]
編譯器總是將二維數(shù)組看成是一個一維數(shù)組,而一維數(shù)組的每個元素又都是一個數(shù)組。

多維數(shù)組定義的下標從前到后可以看做是最宏觀的維到最微觀的維
例:三維數(shù)組 a[i][j][k] 可理解為 共有 i 個大組,每個大組里有 j 個小組,每個小組里有k個元素。
所以:
a 表示為整個三維數(shù)組,其值為 &a[0][0][0]
&a+1 為整個三維數(shù)組后面的第一個位置。(偏移整個三維數(shù)組的長度)
a+1 為第二個大組的首位置處(偏移一個大組的長度)
【數(shù)組名a代表的是數(shù)組首元素的首地址,即:第一個大組的首地址】

a[0] 表示為三維數(shù)組的 i 個大組中的第一個大組【可看做一個二維數(shù)組】,其值與 &a[0][0][0] 的值相同。
&a[0]+1 為第二個大組的首位置處(偏移一個大組的長度)
a[0]+1 為第一個大組中第二個小組的首位置處(a[0]可看做是一個二維數(shù)組名,故其代表的是第一個小組的首地址)(偏移一個小組的長度)

a[0][0] 表示為第一個大組中的第一個小組【可看做一個一維數(shù)組】,其值與 &a[0][0][0] 的值相同。
&a[0][0]+1 為第一個大組中第二個小組的首位置處(偏移一個小組的長度)
a[0][0]+1 為第一個大組中第一個小組的第二個元素位置處(偏移一個元素的長度)
a[0][0][0] 表示為第一個大組中的第一個小組中的第一個元素。其值為&a[0][0][0],a[0][0][0]+1為首元素值加1。(因為a[0][0][0]為元素值而不是地址)

數(shù)組的數(shù)組名(即:二維數(shù)組名)退化為數(shù)組的(常量)指針,而不是指針的指針。 同理, n 維數(shù)組名退化為 n-1 維數(shù)組的(常量)指針。
【總結(jié):指針代表的是誰的首地址 就以誰的長度為偏移單位?!?br /> 【規(guī)律:與定義比較,缺少幾對方括號,就是幾維數(shù)組的數(shù)組名,如上例:a缺少3對方括號,即為3維數(shù)組的數(shù)組名(代表的是2維數(shù)組的地址);a[0]缺少2對方括號,即為2維數(shù)組的數(shù)組名(代表的是1維數(shù)組的地址);a[0][0]缺少1對方括號,即為1維數(shù)組的數(shù)組名(代表的是數(shù)組元素的地址)】

【數(shù)組名與整數(shù)相加,首先要轉(zhuǎn)換成數(shù)組的首元素地址與整數(shù)相加,而首元素的存儲大小就是相加的單位】

對多維數(shù)組的解析

我們可以用上面那種從前到后的解析方式來思考,
a:就表示整個多維數(shù)組。
a[m]:就表示第m+1大組(大組即數(shù)組最大的維),
a[m][n]:就表示第m+1大組中的第n+1小組。(小組即次大的維),
以此類推,即多維數(shù)組的解析是層層細化的。

指針數(shù)組與數(shù)組指針

指針數(shù)組:首先它是一個數(shù)組。數(shù)組的元素都是指針。它是“存儲指針的數(shù)組”的簡稱。
數(shù)組指針:首先它是一個指針。它指向一個數(shù)組。它是“指向數(shù)組的指針”的簡稱。

例:
int p1[10]; //它是指針數(shù)組。(因為[]的優(yōu)先級比*高,p1先與[]結(jié)合,構(gòu)成一個數(shù)組的定義)
int (*p2)[10] ; //它是數(shù)組指針。(括號的優(yōu)先級較高,*與p2構(gòu)成一個指針的定義) 它指向一個包含10個int型數(shù)據(jù)的數(shù)組。
int (\
p)[10][5] ; //則p指向一個int型的二維數(shù)組a[10][5]。
【規(guī)律:數(shù)組指針,把定義中括號內(nèi)的指針看成是一個普通的字母,則其表示的就是 數(shù)組指針所指的對象類型】

int a[5][5] ;
int (*p)[4] ;
p=a ;
問:&p[4][2]-&a[4][2]的值為多少?

設(shè)二維數(shù)組的首地址為0,則a[4][2]為第5組的第3個位置,因為int a[5][5];即有5組,每組有5個元素。故:&a[4][2]是(4*5+2)*sizeof(int)。
int (*p)[4] ; 指針指向一個含4個int型的元素的數(shù)組,故p[4]相對于p[0]向后移動了“4個int型數(shù)組”的長度,然后在此基礎(chǔ)上再向后移動2個int型的長度(即,其步長按維度逐步遞減,多維數(shù)組也可按此方式理解)。最后其值為(4*4+2) sizeof(int)
最后切記:地址值參與的加減運算(地址不能被乘),整數(shù)的單位是地址值代表的元素的存儲大??!
&p[4][2]-&a[4][2]結(jié)果為-4。若分開比較&p[4][2]和&a[4][2]則相差4
sizeof(int)個字節(jié)。

數(shù)組參數(shù)與指針參數(shù)

1、二維數(shù)組名做實參

int  main(void)  
{
    int  a[4][5] ;  
    ………  
    ………  
    fun(a);  
    ………  
}  
被調(diào)函數(shù):  
①fun( inta[4][5] )  
②fun( inta[ ][5] )  
③fun( int(*a)[5] )  
{   ………  
    a[i][j]=………  
    ………  
} 

以上三種方式皆可。無論是那種方式,它們只是寫法不同,但編譯器的處理方式相同,都把它們看做是一維數(shù)組指針。
因為二維數(shù)組名退化為一個一維數(shù)組指針,故是以一維數(shù)組指針的形式來傳遞二維數(shù)組的。

2、指針數(shù)組做實參

int main(void)  
{
    int  a[4][5] , i, *p[4] ;  
    for(i=0;i<4; i++)  
        p[i]= a[i] ;  
    ………  
    fun(p);  
    ………  
}  
被調(diào)函數(shù):  
①fun(int*q[4])  
②fun(int *q[])  
③fun(int **q)  
{   ……… 
    q[i][j]=……… //取出指針數(shù)組中的第i個元素(為指針),再偏移j個單位 
    ………  
} 

以上三種方式皆可。無論是那種方式,寫法不同,但編譯器的處理方式相同,都把它們看做是二級指針。
因為指針數(shù)組名退化為數(shù)組首元素的地址,即二級指針,故是以二級指針的形式來傳遞指針數(shù)組的。
而多維數(shù)組名退化為次維數(shù)組的指針,即數(shù)組指針,故是以數(shù)組指針的形式來傳遞多維數(shù)組的。
【C中函數(shù)實參與形參之間是傳值引用的,所以你要改變實參的值,就傳遞它的地址】