1.什么是指針數(shù)組和數(shù)組指針?
- 指針數(shù)組:指針數(shù)組可以說成是”指針的數(shù)組”,首先這個(gè)變量是一個(gè)數(shù)組,其次,”指針”修飾這個(gè)數(shù)組,意思是說這個(gè)數(shù)組的所有元素都是指針類型,在32位系統(tǒng)中,指針占四個(gè)字節(jié)。
- 數(shù)組指針:數(shù)組指針可以說成是”數(shù)組的指針”,首先這個(gè)變量是一個(gè)指針,其次,”數(shù)組”修飾這個(gè)指針,意思是說這個(gè)指針存放著一個(gè)數(shù)組的首地址,或者說這個(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í),沒有記住運(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]),不過在定義之前一定要清楚自己定義的變量,如果目的是一個(gè)數(shù)組,那就把a(bǔ)rr[4]括起來,如果是一個(gè)指針,就把*arr括起來。如果是看到一段這樣的代碼,可以從他的初始化來分別它是數(shù)組還是指針,很明顯,我這定義的是一個(gè)數(shù)組,如果是指針,會(huì)用NULL來初始化。)
這個(gè)指針數(shù)組有多大呢?答案是16個(gè)字節(jié),因?yàn)樗且粋€(gè)指針數(shù)組。(這是廢話,正話下面說)
每當(dāng)出現(xià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)陋但能說明意思的內(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è)指針,所以說它的四個(gè)元素各占四個(gè)字節(jié),所以變量arr的大小是16個(gè)字節(jié)。
那么就有人問了?初始化arr的{“hello”, “world”, “shannxi”, “xian”};的是什么鬼?
這四個(gè)不是什么鬼,他們也存在在內(nèi)存中,只是跟arr這個(gè)變量不在同一段空間,它們被分配在只讀數(shù)據(jù)區(qū) ,數(shù)組arr[4]的四個(gè)指針元素,分別存放著這四個(gè)字符串的首地址,想象一下,從棧區(qū)有四只無形的手指向數(shù)據(jù)區(qū)的空間。arr+1會(huì)跳過四個(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ù)組指針
首先來定義一個(gè)數(shù)組指針,既然是指針,名字就叫pa
char (*pa)[4];
如果指針數(shù)組和數(shù)組指針這倆個(gè)變量名稱一樣就會(huì)是這樣:char *pa[4]和char (*pa)[4],原來指針數(shù)組和數(shù)組指針的形成的根本原因就是運(yùn)算符的優(yōu)先級(jí)問題,所以定義變量是一定要注意這個(gè)問題,否則定義變量會(huì)有根本性差別!
pa是一個(gè)指針指向一個(gè)char [4]的數(shù)組,每個(gè)數(shù)組元素是一個(gè)char類型的變量,所以我們不妨可以寫成:char[4] (*pa);這樣就可以直觀的看出pa的指向的類型,不過在編輯器中不要這么寫,因?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ù)組用來接收每個(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ù)組過去,如果數(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ù)組中存放的是指針,通過比較指針指向的空間的大小,排序這些空間的地址 。函數(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è)指針,那么就是用來接收地址,在傳參時(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ù)組的首元素首地址
|