2020-04-29 C語(yǔ)言中的數(shù)組指針和指針數(shù)組

數(shù)組指針和指針數(shù)組的區(qū)別

數(shù)組指針(也稱(chēng)行指針)

定義 int (*p)[n];

()優(yōu)先級(jí)高衣赶,首先說(shuō)明p是一個(gè)指針平委,指向一個(gè)整型的一維數(shù)組画拾,這個(gè)一維數(shù)組的長(zhǎng)度是n啥繁,也可以說(shuō)是p的步長(zhǎng)。也就是說(shuō)執(zhí)行p+1時(shí)青抛,p要跨過(guò)n個(gè)整型數(shù)據(jù)的長(zhǎng)度旗闽。

如要將二維數(shù)組賦給一指針,應(yīng)這樣賦值:

int a[3][4];

int (*p)[4]; //該語(yǔ)句是定義一個(gè)數(shù)組指針蜜另,指向含4個(gè)元素的一維數(shù)組适室。

p=a;??????? //將該二維數(shù)組的首地址賦給p,也就是a[0]或&a[0][0]

p++;?????? //該語(yǔ)句執(zhí)行過(guò)后举瑰,也就是p=p+1;p跨過(guò)行a[0][]指向了行a[1][]

所以數(shù)組指針也稱(chēng)指向一維數(shù)組的指針捣辆,亦稱(chēng)行指針。

指針數(shù)組

定義 int *p[n];

[]優(yōu)先級(jí)高此迅,先與p結(jié)合成為一個(gè)數(shù)組汽畴,再由int*說(shuō)明這是一個(gè)整型指針數(shù)組,它有n個(gè)指針類(lèi)型的數(shù)組元素耸序。這里執(zhí)行p+1時(shí)忍些,則p指向下一個(gè)數(shù)組元素,這樣賦值是錯(cuò)誤的:p=a坎怪;因?yàn)閜是個(gè)不可知的表示罢坝,只存在p[0]、p[1]芋忿、p[2]...p[n-1],而且它們分別是指針變量可以用來(lái)存放變量地址炸客。但可以這樣 *p=a; 這里*p表示指針數(shù)組第一個(gè)元素的值,a的首地址的值戈钢。

如要將二維數(shù)組賦給一指針數(shù)組:

int *p[3];

int a[3][4];

p++;?//該語(yǔ)句表示p數(shù)組指向下一個(gè)數(shù)組元素。注:此數(shù)組每一個(gè)元素都是一個(gè)指針

for(i=0;i<3;i++)

p[i]=a[i]

這里int *p[3] 表示一個(gè)一維數(shù)組內(nèi)存放著三個(gè)指針變量是尔,分別是p[0]殉了、p[1]、p[2]

所以要分別賦值拟枚。

這樣兩者的區(qū)別就豁然開(kāi)朗了薪铜,數(shù)組指針只是一個(gè)指針變量众弓,似乎是C語(yǔ)言里專(zhuān)門(mén)用來(lái)指向二維數(shù)組的,它占有內(nèi)存中一個(gè)指針的存儲(chǔ)空間隔箍。指針數(shù)組是多個(gè)指針變量谓娃,以數(shù)組形式存在內(nèi)存當(dāng)中,占有多個(gè)指針的存儲(chǔ)空間蜒滩。

還需要說(shuō)明的一點(diǎn)就是滨达,同時(shí)用來(lái)指向二維數(shù)組時(shí),其引用和用數(shù)組名引用都是一樣的俯艰。

比如要表示數(shù)組中i行j列一個(gè)元素:

*(p[i]+j)捡遍、*(*(p+i)+j)、(*(p+i))[j]竹握、p[i][j]

優(yōu)先級(jí):()>[]>*



一画株、指針數(shù)組和數(shù)組指針的內(nèi)存布局

初學(xué)者總是分不出指針數(shù)組與數(shù)組指針的區(qū)別。其實(shí)很好理解:

指針數(shù)組:首先它是一個(gè)數(shù)組啦辐,數(shù)組的元素都是指針谓传,數(shù)組占多少個(gè)字節(jié)由數(shù)組本身的大小決定,每一個(gè)元素都是一個(gè)指針芹关,在32 位系統(tǒng)下任何類(lèi)型的指針永遠(yuǎn)是占4 個(gè)字節(jié)续挟。它是“儲(chǔ)存指針的數(shù)組”的簡(jiǎn)稱(chēng)。

數(shù)組指針:首先它是一個(gè)指針充边,它指向一個(gè)數(shù)組庸推。在32 位系統(tǒng)下任何類(lèi)型的指針永遠(yuǎn)是占4 個(gè)字節(jié),至于它指向的數(shù)組占多少字節(jié)浇冰,不知道贬媒,具體要看數(shù)組大小。它是“指向數(shù)組的指針”的簡(jiǎn)稱(chēng)肘习。

下面到底哪個(gè)是數(shù)組指針际乘,哪個(gè)是指針數(shù)組呢:

A)

int *p1[10];

B)

int (*p2)[10];

每次上課問(wèn)這個(gè)問(wèn)題,總有弄不清楚的漂佩。這里需要明白一個(gè)符號(hào)之間的優(yōu)先級(jí)問(wèn)題脖含。

“[]”的優(yōu)先級(jí)比“*”要高。p1 先與“[]”結(jié)合投蝉,構(gòu)成一個(gè)數(shù)組的定義养葵,數(shù)組名為p1,int *修飾的是數(shù)組的內(nèi)容瘩缆,即數(shù)組的每個(gè)元素关拒。那現(xiàn)在我們清楚,這是一個(gè)數(shù)組,其包含10 個(gè)指向int 類(lèi)型數(shù)據(jù)的指針着绊,即指針數(shù)組谐算。至于p2 就更好理解了,在這里“()”的優(yōu)先級(jí)比“[]”高归露,“*”號(hào)和p2 構(gòu)成一個(gè)指針的定義洲脂,指針變量名為p2,int 修飾的是數(shù)組的內(nèi)容剧包,即數(shù)組的每個(gè)元素恐锦。數(shù)組在這里并沒(méi)有名字,是個(gè)匿名數(shù)組玄捕。那現(xiàn)在我們清楚p2 是一個(gè)指針踩蔚,它指向一個(gè)包含10 個(gè)int 類(lèi)型數(shù)據(jù)的數(shù)組,即數(shù)組指針枚粘。我們可以借助下面的圖加深理解:

二馅闽、int (*)[10] p2-----也許應(yīng)該這么定義數(shù)組指針

這里有個(gè)有意思的話(huà)題值得探討一下:平時(shí)我們定義指針不都是在數(shù)據(jù)類(lèi)型后面加上指針變量名么?這個(gè)指針p2 的定義怎么不是按照這個(gè)語(yǔ)法來(lái)定義的呢馍迄?也許我們應(yīng)該這樣來(lái)定義p2:

? ?int (*)[10] p2;

int (*)[10]是指針類(lèi)型福也,p2 是指針變量。這樣看起來(lái)的確不錯(cuò)攀圈,不過(guò)就是樣子有些別扭暴凑。其實(shí)數(shù)組指針的原型確實(shí)就是這樣子的,只不過(guò)為了方便與好看把指針變量p2 前移了而已赘来。你私下完全可以這么理解這點(diǎn)现喳。雖然編譯器不這么想。^_^

三犬辰、再論a 和&a 之間的區(qū)別

既然這樣嗦篱,那問(wèn)題就來(lái)了。前面我們講過(guò)a 和&a 之間的區(qū)別幌缝,現(xiàn)在再來(lái)看看下面的代碼:

int main()

{

? ?char a[5]={'A','B','C','D'};

? ?char (*p3)[5] = &a;

? ?char (*p4)[5] = a;

? ?return 0;

}

上面對(duì)p3 和p4 的使用灸促,哪個(gè)正確呢?p3+1 的值會(huì)是什么涵卵?p4+1 的值又會(huì)是什么浴栽?毫無(wú)疑問(wèn),p3 和p4 都是數(shù)組指針轿偎,指向的是整個(gè)數(shù)組典鸡。&a 是整個(gè)數(shù)組的首地址,a是數(shù)組首元素的首地址坏晦,其值相同但意義不同椿每。在C 語(yǔ)言里伊者,賦值符號(hào)“=”號(hào)兩邊的數(shù)據(jù)類(lèi)型必須是相同的英遭,如果不同需要顯示或隱式的類(lèi)型轉(zhuǎn)換间护。p3 這個(gè)定義的“=”號(hào)兩邊的數(shù)據(jù)類(lèi)型完全一致,而p4 這個(gè)定義的“=”號(hào)兩邊的數(shù)據(jù)類(lèi)型就不一致了挖诸。左邊的類(lèi)型是指向整個(gè)數(shù)組的指針汁尺,右邊的數(shù)據(jù)類(lèi)型是指向單個(gè)字符的指針。在Visual C++6.0 上給出如下警告:

? ?warning C4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'多律。

還好痴突,這里雖然給出了警告,但由于&a 和a 的值一樣狼荞,而變量作為右值時(shí)編譯器只是取變量的值辽装,所以運(yùn)行并沒(méi)有什么問(wèn)題。不過(guò)我仍然警告你別這么用相味。

既然現(xiàn)在清楚了p3 和p4 都是指向整個(gè)數(shù)組的拾积,那p3+1 和p4+1 的值就很好理解了。

但是如果修改一下代碼丰涉,把數(shù)組大小改小點(diǎn)拓巧,會(huì)有什么問(wèn)題?p3+1 和p4+1 的值又是多少呢一死?

int main()

{

? ?char a[5]={'A','B','C','D'};

? ?char (*p3)[3] = &a;

? ?char (*p4)[3] = a;

? ?return 0;

}

甚至還可以把代碼再修改肛度,把數(shù)組大小改大點(diǎn):

int main()

{

? ?char a[5]={'A','B','C','D'};

? ?char (*p3)[10] = &a;

? ?char (*p4)[10] = a;

? ?return 0;

}

這個(gè)時(shí)候又會(huì)有什么樣的問(wèn)題?p3+1 和p4+1 的值又是多少投慈?

上述幾個(gè)問(wèn)題承耿,希望讀者能仔細(xì)考慮考慮,并且上機(jī)測(cè)試看看結(jié)果伪煤。

測(cè)試結(jié)果:

(1).char (*p2)[5]=a;必須使用強(qiáng)制轉(zhuǎn)換,如:char (*p2)[5]=(char (*)[5])a;

(2).把數(shù)組大小改變,都會(huì)編譯不通過(guò),提示:

error C2440: 'initializing' : cannot convert from 'char (*)[5]' to 'char (*)[3]'

error C2440: 'initializing' : cannot convert from 'char (*)[5]' to 'char (*)[10]'

(3).把以上程序測(cè)試代碼如下:

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

結(jié)論:

根據(jù)指針類(lèi)型及所指對(duì)象,表示指針大小,每次加1,表示增加指針類(lèi)型大小的字節(jié).----后面還會(huì)有解釋說(shuō)明.

四加袋、地址的強(qiáng)制轉(zhuǎn)換

先看下面這個(gè)例子:

struct Test

{

? ?int Num;

? ?char *pcName;

? ?short sDate;

? ?char cha[2];

? ?short sBa[4];

}*p;

假設(shè)p 的值為0x100000。如下表表達(dá)式的值分別為多少带族?

? ?p + 0x1 = 0x___ ?

? ?(unsigned long)p + 0x1 = 0x___?

? ?(unsigned int*)p + 0x1 = 0x___?

我相信會(huì)有很多人一開(kāi)始沒(méi)看明白這個(gè)問(wèn)題是什么意思锁荔。其實(shí)我們?cè)僮屑?xì)看看,這個(gè)知識(shí)點(diǎn)似曾相識(shí)蝙砌。一個(gè)指針變量與一個(gè)整數(shù)相加減阳堕,到底該怎么解析呢?

還記得前面我們的表達(dá)式“a+1”與“&a+1”之間的區(qū)別嗎择克?其實(shí)這里也一樣恬总。指針變量與一個(gè)整數(shù)相加減并不是用指針變量里的地址直接加減這個(gè)整數(shù)。這個(gè)整數(shù)的單位不是byte 而是元素的個(gè)數(shù)肚邢。所以:p + 0x1 的值為0x100000+sizof(Test)*0x1壹堰。至于此結(jié)構(gòu)體的大小為20byte拭卿,前面的章節(jié)已經(jīng)詳細(xì)講解過(guò)。所以p +0x1 的值為:0x100014贱纠。

(unsigned long)p + 0x1 的值呢峻厚?這里涉及到強(qiáng)制轉(zhuǎn)換,將指針變量p 保存的值強(qiáng)制轉(zhuǎn)換成無(wú)符號(hào)的長(zhǎng)整型數(shù)谆焊。任何數(shù)值一旦被強(qiáng)制轉(zhuǎn)換惠桃,其類(lèi)型就改變了。所以這個(gè)表達(dá)式其實(shí)就是一個(gè)無(wú)符號(hào)的長(zhǎng)整型數(shù)加上另一個(gè)整數(shù)辖试。所以其值為:0x100001辜王。

(unsigned int*)p + 0x1 的值呢?這里的p 被強(qiáng)制轉(zhuǎn)換成一個(gè)指向無(wú)符號(hào)整型的指針罐孝。所以其值為:0x100000+sizof(unsigned int)*0x1呐馆,等于0x100004。

上面這個(gè)問(wèn)題似乎還沒(méi)啥技術(shù)含量莲兢,下面就來(lái)個(gè)有技術(shù)含量的:在x86 系統(tǒng)下汹来,其值為多少?

intmain()

{

? ?int a[4]={1,2,3,4};

? ?int *ptr1=(int *)(&a+1);//指向a數(shù)組后面的內(nèi)存單元怒见,&a+1表示向后移16個(gè)存儲(chǔ)單元

???int *ptr2=(int *)((int)a+1);//表示a的存儲(chǔ)單元的地址增加一個(gè)字節(jié)

? ?printf("%x,%x",ptr1[-1],*ptr2);//ptr1[-1]其實(shí)指向的是a數(shù)組的最后一個(gè)單元俗慈,*ptr1則表示a數(shù)組的地址后移一個(gè)字節(jié)之后的4個(gè)連續(xù)存儲(chǔ)單元所存儲(chǔ)的值

???return 0;

}

這是我講課時(shí)一個(gè)學(xué)生問(wèn)我的題,他在網(wǎng)上看到的遣耍,據(jù)說(shuō)難倒了n 個(gè)人闺阱。我看題之后告訴他,這些人肯定不懂匯編舵变,一個(gè)懂匯編的人酣溃,這種題實(shí)在是小case。下面就來(lái)分析分析這個(gè)問(wèn)題:

根據(jù)上面的講解纪隙,&a+1 與a+1 的區(qū)別已經(jīng)清楚赊豌。

ptr1:將&a+1 的值強(qiáng)制轉(zhuǎn)換成int*類(lèi)型,賦值給int* 類(lèi)型的變量ptr绵咱,ptr1 肯定指到數(shù)組a 的下一個(gè)int 類(lèi)型數(shù)據(jù)了碘饼。ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 個(gè)byte悲伶。所以其值為0x4艾恼。

ptr2:按照上面的講解,(int)a+1 的值是元素a[0]的第二個(gè)字節(jié)的地址麸锉。然后把這個(gè)地址強(qiáng)制轉(zhuǎn)換成int*類(lèi)型的值賦給ptr2钠绍,也就是說(shuō)*ptr2 的值應(yīng)該為元素a[0]的第二個(gè)字節(jié)開(kāi)始的連續(xù)4 個(gè)byte 的內(nèi)容。

其內(nèi)存布局如下圖:

好花沉,問(wèn)題就來(lái)了柳爽,這連續(xù)4 個(gè)byte 里到底存了什么東西呢媳握?也就是說(shuō)元素a[0],a[1]里面的值到底怎么存儲(chǔ)的。這就涉及到系統(tǒng)的大小端模式了磷脯,如果懂匯編的話(huà)蛾找,這根本就不是問(wèn)題。既然不知道當(dāng)前系統(tǒng)是什么模式争拐,那就得想辦法測(cè)試腋粥。大小端模式與測(cè)試的方法在第一章講解union 關(guān)鍵字時(shí)已經(jīng)詳細(xì)討論過(guò)了,請(qǐng)翻到彼處參看架曹,這里就不再詳述。我們可以用下面這個(gè)函數(shù)來(lái)測(cè)試當(dāng)前系統(tǒng)的模式闹瞧。

int?checkSystem()

{

union check

{

int?i;

char?ch;

}?c;

c.i = 1;

return (c.ch ==1);//如果當(dāng)前系統(tǒng)為大端模式這個(gè)函數(shù)返回0绑雄;如果為小端模式,函數(shù)返回1奥邮。

}

如果當(dāng)前系統(tǒng)為大端模式這個(gè)函數(shù)返回0万牺;如果為小端模式,函數(shù)返回1洽腺。也就是說(shuō)如果此函數(shù)的返回值為1 的話(huà)脚粟,*ptr2 的值為0x2000000。如果此函數(shù)的返回值為0 的話(huà)蘸朋,*ptr2 的值為0x100核无。




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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市藕坯,隨后出現(xiàn)的幾起案子团南,更是在濱河造成了極大的恐慌,老刑警劉巖炼彪,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吐根,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡辐马,警方通過(guò)查閱死者的電腦和手機(jī)拷橘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)喜爷,“玉大人冗疮,你說(shuō)我怎么就攤上這事≌攴埽” “怎么了赌厅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)轿塔。 經(jīng)常有香客問(wèn)我特愿,道長(zhǎng)仲墨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任揍障,我火速辦了婚禮目养,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毒嫡。我一直安慰自己癌蚁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布兜畸。 她就那樣靜靜地躺著努释,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咬摇。 梳的紋絲不亂的頭發(fā)上伐蒂,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音肛鹏,去河邊找鬼逸邦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛在扰,可吹牛的內(nèi)容都是我干的缕减。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼芒珠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桥狡!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起妓局,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤总放,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后好爬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體局雄,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年存炮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炬搭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡穆桂,死狀恐怖宫盔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情享完,我是刑警寧澤灼芭,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站般又,受9級(jí)特大地震影響彼绷,放射性物質(zhì)發(fā)生泄漏巍佑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一寄悯、第九天 我趴在偏房一處隱蔽的房頂上張望萤衰。 院中可真熱鬧,春花似錦猜旬、人聲如沸脆栋。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)椿争。三九已至,卻和暖如春秘遏,著一層夾襖步出監(jiān)牢的瞬間丘薛,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工邦危, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舍扰。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓倦蚪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親边苹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陵且,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355