|
C語言中的精華是什么,答曰指針,這也是C語言中唯一的難點。
C是對底層操作非常方便的語言,而底層操作中用到最多的就是指針,以后從事嵌入式開發(fā)的朋友們,指針將陪伴我們終身。
本文將從八個常見的方面來透視C語言中的指針,當(dāng)然,還有其他沒有具體提到的方面,像指針表達(dá)式、指針安全等問題,以后有機(jī)會我再慢慢補(bǔ)充。
還是那句老話,重要的是實踐,多寫代碼,才是學(xué)好C語言的關(guān)鍵。
1.指針類型分析
分析指針,可以從變量名處起,根據(jù)運算符優(yōu)先級結(jié)合,一步一步分析.
int p;//這是一個普通的整型變量
int *p;//首先從P處開始,先與*結(jié)合,所以說明P是一個指針,然后再與int結(jié)合,說明指針?biāo)赶虻膬?nèi)容的類型為int 型.所以 P是一個返回整型數(shù)據(jù)的指針
int p[3]; //首先從P處開始,先與[]結(jié)合,說明P 是一個數(shù)組,然后與int結(jié)合,說明數(shù)組里的元素是整型的,所以 P是一個由整型數(shù)據(jù)組成的數(shù)組
int *p[3]; //首先從P處開始,先與[]結(jié)合,因為其優(yōu)先級比*高,所以P是一個數(shù)組,然后再與*結(jié)合,說明數(shù)組里的元素是指針類型,然后再與 int結(jié)合,說明指針?biāo)赶虻膬?nèi)容的類型是整型的,所以是一個由返回整型數(shù)據(jù)的指針?biāo)M成的數(shù)組
int (*p)[3]; //首先從P處開始,先與*結(jié)合,說明P是一個指針然后再與[]結(jié)合(與"()"這步可以忽略,只是為了改變優(yōu)先級),說明指針?biāo)赶虻膬?nèi)容是一個數(shù)組,然后再與int 結(jié)合,說明數(shù)組里的元素是整型的.所以P是一個指向由整型數(shù)據(jù)組成的數(shù)組的指針
int **p; //首先從 P開始,先與*結(jié)合,說明P是一個指針,然后再與*結(jié)合,說明指針?biāo)赶虻脑厥侵羔?然后再與 int結(jié)合,說明該指針?biāo)赶虻脑厥钦蛿?shù)據(jù). 所以P是一個返回指向整型數(shù)據(jù)的指針的指針
int p(int);//從P處起,先與()結(jié)合,說明P是一個函數(shù),然后進(jìn)入()里分析,說明該函數(shù)有一個整型變量的參數(shù)然后再與外面的int 結(jié)合,說明函數(shù)的返回值是一個整型數(shù)據(jù).所以P是一個有整型參數(shù)且返回類型為整型的函數(shù)
int (*p)(int); //從P處開始,先與指針結(jié)合,說明P是一個指針,然后與()結(jié)合,說明指針指向的是一個函數(shù),然后再與()里的int 結(jié)合,說明函數(shù)有一個int 型的參數(shù),再與最外層的int 結(jié)合,說明函數(shù)的返回類型是整型,所以P是一個指向有一個整型參數(shù)且返回類型為整型的函數(shù)的指針
int *(*p(int))[3]; //從 P開始,先與()結(jié)合,說明P是一個函數(shù),然后進(jìn)入()里面,與int結(jié)合,說明函數(shù)有一個整型變量參數(shù),然后再與外面的*結(jié)合,說明函數(shù)返回的是一個指針,,然后到最外面一層,先與[]結(jié)合,說明返回的指針指向的是一個數(shù)組,然后再與*結(jié)合,說明數(shù)組里的元素是指針,然后再與int 結(jié)合,說明指針指向的內(nèi)容是整型數(shù)據(jù).所以P是一個參數(shù)為一個整數(shù)且返回一個指向由整型指針變量組成的數(shù)組的指針變量的函數(shù)
2.指針分析
指針是一個特殊的變量,它里面存儲的數(shù)值被解釋成為內(nèi)存里的一個地址。
要搞清一個指針需要搞清指針的四方面的內(nèi)容:指針的類型、指針?biāo)赶虻念愋汀⒅羔樀闹祷蛘呓兄羔標(biāo)赶虻膬?nèi)存區(qū)、指針本身所占據(jù)的內(nèi)存區(qū)。
指針的類型:把指針聲明語句里的指針名字去掉,剩下的部分就是這個指針的類型
指針?biāo)赶虻念愋停喊阎羔樎暶髡Z句中的指針名字和名字左邊的指針聲明符*去掉,剩下的就是指針?biāo)赶虻念愋停ㄔ谥羔樀乃阈g(shù)運算中,指針?biāo)赶虻念愋陀泻艽蟮淖饔茫?br />
指針?biāo)赶虻膬?nèi)存區(qū):從指針的值所代表的那個內(nèi)存地址開始,長度為sizeof(指針?biāo)赶虻念愋?的一片內(nèi)存區(qū)。(一個指針指向了某塊內(nèi)存區(qū)域,就相當(dāng)于說該指針的值是這塊內(nèi)存區(qū)域的首地址)
指針本身所占據(jù)的內(nèi)存區(qū):用函數(shù)sizeof(指針的類型)可以測出指針本身所占據(jù)的內(nèi)存區(qū)(在 32位平臺里,指針本身占據(jù)了 4個字節(jié)的長度)
3.指針的算術(shù)運算
指針和整數(shù)進(jìn)行加減:一個指針 ptrold加(減)一個整數(shù) n后,結(jié)果是一個新的指針ptrnew,ptrnew 的類型和 ptrold 的類型相同,ptrnew 所指向的類型和 ptrold所指向的類型也相同,ptrnew的值將比 ptrold 的值增加(減少)了n乘sizeof(ptrold所指向的類型)個字節(jié)。
指針和指針進(jìn)行加減:兩個指針不能進(jìn)行加法運算,這是非法操作;兩個指針可以進(jìn)行減法操作,但必須類型相同,一般用在數(shù)組方面。
4. 運算符&和*
&是取地址運算符,*是間接運算符。
&a的運算結(jié)果是一個指針,指針的類型是a的類型加個*,指針?biāo)赶虻念愋褪莂的類型,指針?biāo)赶虻牡刂仿铮蔷褪莂的地址。
*p的運算結(jié)果就五花八門了,總之*p 的結(jié)果是 p 所指向的東西,這個東西有這些特點:它的類型是 p指向的類型,它所占用的地址是p所指向的地址。
5. 數(shù)組和指針的關(guān)系
數(shù)組的數(shù)組名其實可以看作一個指針。
聲明了一個數(shù)組 TYPE array[n],則數(shù)組名稱array就有了兩重含義:
第一,它代表整個數(shù)組,它的類型是 TYPE[n];
第二 ,它是一個常量指針,該指針的類型是TYPE*,該指針指向的類型是 TYPE,也就是數(shù)組單元的類型,該指針指向的內(nèi)存區(qū)就是數(shù)組第0號單元,該指針自己占有單獨的內(nèi)存區(qū),注意它和數(shù)組第0號單元占據(jù)的內(nèi)存區(qū)是不同的。該指針的值是不能修改的,即類似 array++的表達(dá)式是錯誤的。
6. 指針和結(jié)構(gòu)類型的關(guān)系
假設(shè)我們定義了一個結(jié)構(gòu)體,struct MyStruct{inta;int b;int c;};
同時定義結(jié)構(gòu)體的結(jié)構(gòu)對象并初始化,struct MyStructss={20,30,40};
那么我們?nèi)绾瓮ㄟ^指針ptr 來訪問 ss的三個成員變量呢?
答案就是,我們先定義一個指向結(jié)構(gòu)對象 ss的指針,struct MyStruct *ptr=&ss; 然后,使用指向運算符->便可實現(xiàn)對結(jié)構(gòu)對象ss成員的訪問。
ptr->a; //或者可以這們(*ptr).a,建議使用前者
ptr->b;
ptr->c;
7. 指針和函數(shù)的關(guān)系
可以把一個指針聲明成為一個指向函數(shù)的指針,從而通過函數(shù)指針調(diào)用函數(shù)。讓我們舉一個例子來說明以下吧。
int fun(char *,int);
int (*pfun)(char *,int);
pfun=fun;
int a=(*pfun)("abcdefg",7);
例中,定義了一個指向函數(shù)fun的指針pfun,把pfun作為函數(shù)的形參。把指針表達(dá)式作為實參,從而實現(xiàn)了對函數(shù)fun的調(diào)用。
8. 指針類型轉(zhuǎn)換
當(dāng)我們初始化一個指針或給一個指針賦值時,賦值號的左邊是一個指針,賦值號的右邊是一個指針表達(dá)式,這就要求兩邊的類型一致,所指向的類型也一致,如果不一致的話,需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。語法格式是:(TYPE *)p;
這樣強(qiáng)制類型轉(zhuǎn)換的結(jié)果是一個新指針,該新指針的類型是TYPE *,它指向的類型是TYPE,它指向的地址就是原指針指向的地址。要注意的是,原來的指針p的一切屬性都沒有被修改。
另外,一個函數(shù)如果使用了指針作為形參, 那么在函數(shù)調(diào)用語句的實參和形參的結(jié)合過程中,也必須保證類型一致 ,否則需要強(qiáng)制轉(zhuǎn)換。
|
|