1.什么是指針數(shù)組和數(shù)組指針,?
- 指針數(shù)組:指針數(shù)組可以說(shuō)成是”指針的數(shù)組”,首先這個(gè)變量是一個(gè)數(shù)組,,其次,,”指針”修飾這個(gè)數(shù)組,意思是說(shuō)這個(gè)數(shù)組的所有元素都是指針類型,,在32位系統(tǒng)中,,指針占四個(gè)字節(jié)。
- 數(shù)組指針:數(shù)組指針可以說(shuō)成是”數(shù)組的指針”,,首先這個(gè)變量是一個(gè)指針,,其次,”數(shù)組”修飾這個(gè)指針,,意思是說(shuō)這個(gè)指針存放著一個(gè)數(shù)組的首地址,,或者說(shuō)這個(gè)指針指向一個(gè)數(shù)組的首地址。
根據(jù)上面的解釋,,可以了解到指針數(shù)組和數(shù)組指針的區(qū)別,,因?yàn)槎吒揪褪欠N類型的變量,。
2.指針數(shù)組和數(shù)組指針到底是什么?
2.1指針數(shù)組
首先先定義一個(gè)指針數(shù)組,,既然是數(shù)組,,名字就叫arr
char *arr[4] = {"hello", "world", "shannxi", "xian"};
//arr就是我定義的一個(gè)指針數(shù)組,它有四個(gè)元素,,每個(gè)元素是一個(gè)char *類型的指針,,這些指針存放著其對(duì)應(yīng)字符串的首地址。
(當(dāng)一個(gè)變量出現(xiàn)左右都出現(xiàn)一個(gè)運(yùn)算符時(shí),,沒(méi)有記住運(yùn)算符優(yōu)先級(jí)的人就會(huì)糾結(jié)arr變量到底跟哪一個(gè)運(yùn)算符先結(jié)合,。如果是自己定義一個(gè)指針數(shù)組,搞不清楚運(yùn)算符的優(yōu)先級(jí),,那么就加上小括號(hào)(),,比如定義一個(gè)指針數(shù)組,可以寫成char *(arr[4]),,不過(guò)在定義之前一定要清楚自己定義的變量,,如果目的是一個(gè)數(shù)組,那就把a(bǔ)rr[4]括起來(lái),,如果是一個(gè)指針,,就把*arr括起來(lái)。如果是看到一段這樣的代碼,,可以從他的初始化來(lái)分別它是數(shù)組還是指針,,很明顯,我這定義的是一個(gè)數(shù)組,,如果是指針,,會(huì)用NULL來(lái)初始化。)
這個(gè)指針數(shù)組有多大呢,?答案是16個(gè)字節(jié),,因?yàn)樗且粋€(gè)指針數(shù)組。(這是廢話,,正話下面說(shuō))
每當(dāng)出現(xiàn)這些問(wèn)題時(shí),,腦子里一定要第一時(shí)間反應(yīng)出內(nèi)存映像圖
內(nèi)存映像象圖 |
內(nèi)容 |
權(quán)限 |
棧區(qū) |
函數(shù)中的普通變量 |
可讀可寫 |
堆區(qū) |
動(dòng)態(tài)申請(qǐng)的內(nèi)存 |
可讀可寫 |
靜態(tài)變量區(qū) |
static修飾的變量 |
可讀可寫 |
數(shù)據(jù)區(qū) |
用于初始化變量的常量 |
只讀 |
代碼區(qū) |
代碼指令 |
只讀 |
這里最左側(cè)一列是一個(gè)很簡(jiǎn)陋但能說(shuō)明意思的內(nèi)存圖,一般情況下,,從棧區(qū)到代碼區(qū),,是從高地址到低地址。棧向下增長(zhǎng),,堆向上增長(zhǎng),。
arr[4]是一個(gè)在主函數(shù)定義的數(shù)組。把它對(duì)應(yīng)到對(duì)應(yīng)到內(nèi)存中,,arr是一個(gè)在棧區(qū) ,有四個(gè)元素的數(shù)組,,而每一個(gè)數(shù)組又是一個(gè)指針,所以說(shuō)它的四個(gè)元素各占四個(gè)字節(jié),,所以變量arr的大小是16個(gè)字節(jié),。
那么就有人問(wèn)了?初始化arr的{“hello”, “world”, “shannxi”, “xian”};的是什么鬼,?
這四個(gè)不是什么鬼,,他們也存在在內(nèi)存中,只是跟arr這個(gè)變量不在同一段空間,,它們被分配在只讀數(shù)據(jù)區(qū) ,,數(shù)組arr[4]的四個(gè)指針元素,分別存放著這四個(gè)字符串的首地址,,想象一下,,從棧區(qū)有四只無(wú)形的手指向數(shù)據(jù)區(qū)的空間。arr+1會(huì)跳過(guò)四個(gè)字節(jié),,,。也就是一個(gè)指針的大小
這就相當(dāng)與定義char *p1 = “hello”,char *p1 = “world”,,char *p3 = “shannxi”,, char *p4 = “xian”,這是四個(gè)指針,,每個(gè)指針存放一個(gè)字符串首地址,,然后用arr[4]這個(gè)數(shù)組分別存放這四個(gè)指針,就形成了指針數(shù)組,。
2.2數(shù)組指針
首先來(lái)定義一個(gè)數(shù)組指針,,既然是指針,名字就叫pa
char (*pa)[4];
如果指針數(shù)組和數(shù)組指針這倆個(gè)變量名稱一樣就會(huì)是這樣:char *pa[4]和char (*pa)[4],,原來(lái)指針數(shù)組和數(shù)組指針的形成的根本原因就是運(yùn)算符的優(yōu)先級(jí)問(wèn)題,,所以定義變量是一定要注意這個(gè)問(wèn)題,否則定義變量會(huì)有根本性差別,!
pa是一個(gè)指針指向一個(gè)char [4]的數(shù)組,,每個(gè)數(shù)組元素是一個(gè)char類型的變量,所以我們不妨可以寫成:char[4] (*pa);這樣就可以直觀的看出pa的指向的類型,,不過(guò)在編輯器中不要這么寫,,因?yàn)榫幾g器根本不認(rèn)識(shí),這樣寫只是幫助我們理解,。
既然pa是一個(gè)指針,,存放一個(gè)數(shù)組的地址,那么在我們定義一個(gè)數(shù)組時(shí),,數(shù)組名稱就是這個(gè)數(shù)組的首地址,,那么這二者有什么區(qū)別和聯(lián)系呢,?
char a[4];,
a是一個(gè)長(zhǎng)度為4的字符數(shù)組,,a是這個(gè)數(shù)組的首元素首地址,。既然a是地址,pa是指向數(shù)組的指針,,那么能將a賦值給pa嗎,?答案是不行的!因?yàn)閍是數(shù)組首元素首地址,,pa存放的卻是數(shù)組首地址,,a是char 類型,a+1,,a的值會(huì)實(shí)實(shí)在在的加1,,而pa是char[4]類型的,pa+1,,pa則會(huì)加4,,雖然數(shù)組的首地址和首元素首地址的值相同,但是兩者操作不同,,所以類型不匹配不能直接賦值,,但是可以這樣:pa = &a,pa相當(dāng)與二維數(shù)組的行指針,,現(xiàn)在它指向a[4]的地址,。
3.指針數(shù)組和數(shù)組指針的使用
3.1指針數(shù)組在參數(shù)傳遞時(shí)的使用
指針數(shù)組常用在主函數(shù)傳參 ,在寫主函數(shù)時(shí),,參數(shù)有兩個(gè),,一個(gè)確定參數(shù)個(gè)數(shù),一個(gè)這是指針數(shù)組用來(lái)接收每個(gè)參數(shù)(字符串)的地址
int main(int argc, char *argv[])
此時(shí)可以想象內(nèi)存映像圖,,主函數(shù)的棧區(qū)有一個(gè)叫argv的數(shù)組,,這個(gè)數(shù)組的元素是你輸入的參數(shù)的地址,指向著只讀數(shù)據(jù)區(qū),。
如果是向子函數(shù)傳參 ,,這和傳遞一個(gè)普通數(shù)組的思想一樣,不能傳遞整個(gè)數(shù)組過(guò)去,,如果數(shù)組很大,,這樣內(nèi)存利用率很低,所以應(yīng)該傳遞數(shù)組的首地址,,用一個(gè)指針接收這個(gè)地址,。因此,指針數(shù)組對(duì)應(yīng)著二級(jí)指針
void fun(char **pp);//子函數(shù)中的形參
fun(char *p[]);//主函數(shù)中的實(shí)參
3.2指針數(shù)組的排序
指針數(shù)組的排序非常有趣,,因?yàn)檫@個(gè)數(shù)組中存放的是指針,,通過(guò)比較指針指向的空間的大小,,排序這些空間的地址 。函數(shù)實(shí)現(xiàn)如下:
void sort(char **pa, int n)//冒泡排序
{
int i, j;
char *tmp = NULL;
for(i = 0; i < n-1; i++){
for(j = 0; j < n-1-i; j++){
if((strcmp(*pa+j), *(pa+j+1)) > 0){
tmp = *(pa + j);
*(pa + j) = *(pa + j + 1);
*(pa + j + 1) = tmp;
}
}
}
}
在函數(shù)中定義指針數(shù)組,,并且打印結(jié)果如下:
char *pa[4] = {"abc", "xyz", "opq", "xyz"};
[root@menwen-linux test]# ./test
abc
ijk
opq
xyz
數(shù)組指針傳參時(shí)的使用
數(shù)組指針既然是一個(gè)指針,,那么就是用來(lái)接收地址,在傳參時(shí)就接收數(shù)組的地址,,所以數(shù)組指針對(duì)應(yīng)的是二維數(shù)組。
void fun(int (*P)[4]);//子函數(shù)中的形參,,指針數(shù)組
a[3][4] = {0};//主函數(shù)中定義的二維數(shù)組
fun(a);//主函數(shù)調(diào)用子函數(shù)的實(shí)參,,是二維數(shù)組的首元素首地址
|