版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
1、7.1 我就是地址 地址是內(nèi)存單元的索引。內(nèi)存以字節(jié)為單位進行劃分,字節(jié)是數(shù)據(jù)存儲的基本單位。每個存儲單元都被分配了不同的編號,每個編號唯一對應一個存儲單元。這個編號就是存儲單元的地址,使用這些單元時只需按編號定位即可。如圖7.1即為內(nèi)存中的地址和存儲單元的對應關系。 圖7-1中,1001、1001、1002等即為內(nèi)存的地址,每個地址對應一個存儲單元,每個存儲單元占一個字節(jié)。對存儲單元的訪問都通過這些地址來實現(xiàn)。數(shù)據(jù)存儲到內(nèi)存中時,按照數(shù)據(jù)類型要求的單元數(shù),分配相應的連續(xù)單元。該連續(xù)單元的首地址,即第一個單元的地址就是該變量的存儲地址。第1頁/共77頁圖7-1 地址和存儲單元關系圖第2頁/共7
2、7頁【示例7-1】 定義3個變量,它們在內(nèi)存中的實際存放如圖7-2所示。 int iVal=25185; short sVal=97; char cVal=b;第3頁/共77頁圖7-2 數(shù)據(jù)存儲 分析:其中,iVal是整型數(shù),占4個字節(jié),故10001003這4個字節(jié)的內(nèi)存單元配給了它。25185的二進制表示為01100010 011000012,按低字節(jié)優(yōu)先,存到內(nèi)存中時,即圖7.1所示。sVal占兩字節(jié),被分配到1004開始的兩個單元中。cVal占一個字節(jié),分配到1006單元中。地址1000、1004和1006分別是這3個變量的首地址。第4頁/共77頁 在定義這三個變量時,系統(tǒng)就在符號表中建
3、立了“(變量名,首地址)”對。存取時,系統(tǒng)去符號表中查出變量對應的首地址,然后根據(jù)首地址去內(nèi)存訪問數(shù)據(jù)。最后從內(nèi)存中取出數(shù)據(jù)類型要求的字節(jié)數(shù),并根據(jù)高低字節(jié)優(yōu)先順序轉(zhuǎn)換出最終結(jié)果。例如,取出sVal值的過程為: (1)按變量名查找符號表,取出地址1004; (2)定位到內(nèi)存中地址為1004的單元處; (3)取出short類型要求的連續(xù)2個單元的內(nèi)容,此處為1004和1005兩個單元的內(nèi)容; (4)最后,按照系統(tǒng)是高字節(jié)優(yōu)先還是低字節(jié)優(yōu)先轉(zhuǎn)換出實際的數(shù)據(jù)。 通過上述4步就得到了變量sVal的值97。第5頁/共77頁 實際上,地址本身并不是什么特殊的數(shù)據(jù),而是一個無符號整型數(shù),取值范圍在當前系統(tǒng)的
4、尋址范圍內(nèi)。32 位系統(tǒng)的尋址空間為232,共可以有232個地址。因此,保存一個地址就需要32位,即4個字節(jié)。 如果可以定義一個變量,該變量的內(nèi)容是一個尋址空間范圍內(nèi)的無符號整型數(shù)。通過某種手段告訴系統(tǒng)這是某個內(nèi)存塊的首地址,那么就可以沿著該變量路由到一個內(nèi)存塊。這個無符號整型數(shù)就叫做指針,存放該無符號整型數(shù)的變量就叫做指針變量(常簡稱為指針),并且稱該指針變量指向了該存儲單元。如此,就可以通過指針來間接的訪問一個內(nèi)存單元。例如定義指針變量pChar,在圖7.2內(nèi)為它分配存儲單元1007,1007內(nèi)放變量cVal的地址1006。那么1006就是一個指針,變量pChar指向了內(nèi)存單元1006,通
5、過pChar就可以訪問到cVal的值。第6頁/共77頁 說明:當一個長于一字節(jié)的數(shù)據(jù)保存到內(nèi)存中時,有兩種字節(jié)存儲順序。有體系結(jié)構(gòu)設計者選擇了邏輯順序與物理順序一致,即低字節(jié)優(yōu)先。這叫l(wèi)ittle endian,如Intel x86系列。另一些設計者則選擇了將字節(jié)的邏輯順序與物理順序相反,即高字節(jié)優(yōu)先。這被稱為big endian,如PowerPC。第7頁/共77頁7.2 指針的定義方式 在7.1節(jié)中講到指針是一個32位的無符號整型數(shù),指針變量是保存指針的變量。這一節(jié)就來看一下這個32位無符號整型數(shù)是如何被說明為指針的。第8頁/共77頁7.2.1 指針的定義C+中沒有屬于指針的專用關鍵字,但卻
6、有自己特有的聲明格式。其聲明方法如下所示。type * var;其中,type是指針類型,表示指針指向的內(nèi)存單元中存放的數(shù)據(jù)類型,該類型決定了指針操作時指向地址變化的規(guī)律,也決定了編譯器將把所指向的內(nèi)存塊的內(nèi)容按什么格式來處理。var是指針的變量名,*是指針的標識符。*可以靠近類型說明符,也可以靠近變量名,還可以處在兩者中間,都表示var是一個type型指針。但如果有多個指針時,每一個指針前都必須帶*號。如果不帶*號,就表示是一個type型變量,而不是指針。因此為了清晰,常將*號靠近變量名。第9頁/共77頁【示例7-2】 演示6種指針的定義方式。int * pInt;/整型指針char * p
7、Char;/字符指針float * pFloat;/浮點型指針void * pVoid;/無類型指針short *pShort,myID/定義short型指針pShort,short型非指針變量myIDbool *pBool1, Bool2;/定義一個指針pBool1,一個bool型變量Bool2分析:該示例的第1個指針是整型,表示指針pInt指向的數(shù)據(jù)為整型。第2個是字符型指針,表示pChar指向的數(shù)據(jù)為字符型。第3個是浮點型指針,表示pfloat指向的數(shù)據(jù)為浮點型。第4個是無類型指針,表示pVoid指向的數(shù)據(jù)是無類型的。第5個是短整型指針變量pShort。第6個是bool型指針變量pBoo
8、l1。第10頁/共77頁7.2.2 向左向右分析指針 示例7-2中的第6個定義語句如果是采用示例中的*號靠近變量的風格,則不會引起誤解。如果是采用*號靠近類型說明符或處在兩者中間,則容易引起誤解,容易認為pBoo1和Bool2都是指針。所以,習慣上采用靠近變量的風格。如果采用*號靠近類型的方式,則最好拆分寫成如下格式: bool *pBool1; bool Bool2;第11頁/共77頁 對于short *pShort和short* pShort這兩種聲明方式可以按如下過程理解。 從右向左理解short *pShort:pShort表明變量名是pShort,*pShort表明pShort是指針
9、,short *pShort表明pShort是指向short型數(shù)據(jù)的指針。 從左向右理解short* pShort:short表明是short類型,short*表明是指向short型的指針,short* pShort表明指向short型指針的名稱為pShort。 第二種格式的理解過程只適用于定義中的第一個變量,否則,“short* pShort,myID”語句中的myID就會被理解為short型指針。所以,建議最后采用*號靠近變量的風格,按從右向左理解。第12頁/共77頁7.2.3 看看你有多大sizeof初學者常常分不清某個變量是否是指針,尤其在面對定義復雜的指針時更顯束手無策。這里向讀者介
10、紹一個很有用的運算符sizeof,它可以幫助識別指針。sizeof也是一個運算符,雖然它的用法看起來很像一個函數(shù)。它在編譯時計算,返回的是對象的長度,格式如下:sizeof object或sizeof(object)例如,sizeof int和sizeof(int)都是在測試整型類型的長度,sizeof var和sizeof(var)都是在測試變量var的長度。由于指針所占的字節(jié)數(shù)在同一機型上是定長的,比如在32位機上是32位長,因此可以用它來測試某個變量是否是指針。第13頁/共77頁【示例7-3】 利用sizeof運算來識別指針。 分析:該示例中定義兩個指針變量。第1條輸出語句輸出了4,而c
11、har型數(shù)據(jù)的長度為1,故pChar是指針,*pChar是char型數(shù)據(jù)。第3條輸出語句輸出了4,而第4個輸出了8,表明pDouble是指針,*pDouble是double型數(shù)據(jù)。第14頁/共77頁雖然不能完全用sizeof來區(qū)分指針和非指針,但它可以作為一個有用的輔助手段來適用。要想學好指針,理解指針的涵義,還需要重點注意下面幾個概念。指針:內(nèi)存單元的地址,是常量;指針變量:保存指針的變量,類型依所指向的內(nèi)存單元的數(shù)據(jù)而定,常簡稱為指針;指針本身的類型:指針本身的類型是無符號整型;指針的類型:指針所指向的類型,指針所指向的內(nèi)存單元的數(shù)據(jù)的類型;指針的值:指針所指向的內(nèi)存單元的數(shù)據(jù)內(nèi)容;變量名
12、是直接引用,指針則是間接引用。說明:*號在指針定義中是指針標識,不在定義中與指針在一起表示指針指向的內(nèi)存單元。在7.8節(jié)會詳細講解它的用法。指針與數(shù)組組合時也比較復雜,本書在數(shù)組一章中會有詳細介紹。第15頁/共77頁7.3 指針的種類 指針本身是一個無符號型整數(shù),但是根據(jù)指針指向?qū)ο蟛煌陀梅ǖ牟煌梢苑殖稍S多種。第16頁/共77頁1按指向?qū)ο蟮牟煌瑒澐?如果指針指向的對象是整型數(shù)據(jù),就稱為整型指針。如果指針指向的對象是結(jié)構(gòu)體就叫結(jié)構(gòu)體指針。如果指針指向的是函數(shù)就叫函數(shù)指針。第17頁/共77頁【示例7-4】 定義6種指向不同對象的指針。int *pInt;/整型指針float *pFloat;
13、/浮點型指針char *pChar;/字符型指針char (*pCharArray1)2;/數(shù)組指針char *pCharArray22;/指針數(shù)組char (*pFun)(int num);/函數(shù)指針分析:該示例定義了6類指針,第1個指針指向整型數(shù),叫整型指針。第2個指向浮點型,叫浮點指針。第3個指向字符型,叫字符指針。第4個指向數(shù)組,叫數(shù)組指針。第5個指針本身是數(shù)組,叫指針數(shù)組。最后一個指向的是返回類型為char型,形參為整型的函數(shù)指針。數(shù)組指針和函數(shù)指針的理解比較復雜,在本書后續(xù)章節(jié)講解數(shù)組和函數(shù)時將詳細講解。第18頁/共77頁2按指針的多級性劃分 指針的多級性是按指針所指數(shù)據(jù)是否仍然為
14、指針來劃分的。按這個劃分方法可以將指針分為單級間指和多級間指。單級間指直接指向?qū)ο蟆6嗉夐g指指向的仍然是指針,也叫指針的指針。指針的級數(shù)由指針定義時的指針標識符表示,每出現(xiàn)一個*就增加一級。 1個*表示變量的內(nèi)容是地址,該地址指向的內(nèi)存單元是數(shù)據(jù)。2個*時,第1個*表示變量的內(nèi)容是地址,第2個*表示該地址指向的內(nèi)容仍是地址,這個地址指向的才是數(shù)據(jù)。有幾個*就可以解釋成有幾個地址變換。例如3個表示經(jīng)過3次地址變換才能定位到真正的存儲數(shù)據(jù)的單元。第19頁/共77頁【示例7-5】 指針的多重性舉例。int *pInt1;/單級間指int *pInt2;/兩級間指int *pInt3;/三級間指分析:
15、該示例聲明了3個指針,其中第1個指針直接指向一個保存整型數(shù)據(jù)的內(nèi)存單元,叫做單級間指。第2個指針指向的內(nèi)容仍然是指針,該指針才指向真正的整型數(shù)據(jù),所以叫指針的指針。第3個指針指向的內(nèi)容是指針的指針,也是多級間指。多級間指能延伸到所需要的任何一級,但跟蹤困難,一般二級間指就已足夠。如圖7-3為三個指針的指向圖示。第20頁/共77頁圖7-3 示例7-4的指針指向第21頁/共77頁3按照指針定義后可否改變劃分 按照指針定義后可否改變,可將指針分為指針常量和可變指針。第22頁/共77頁【示例7-6】 指針的可變性舉例。 int iVal;/定義整型變量 int *pInt1;/指針變量 const i
16、nt *pInt2=&iVal;/常量指針,指向可變,所指內(nèi)容不可變 int const *pInt3=&iVal;/常量指針,指向可變,所指內(nèi)容不可變 int *const pInt3=&iVal;/指針常量,指向不可變,所指內(nèi)容可變 const int *const pInt4=& iVal;/指針常量,指向不可變,所指內(nèi)容不可變第23頁/共77頁 分析:該示例定義了5個指針。其中,第1個指針是可變指針,指針指向的內(nèi)容可變,指針的指向也是可變的。第2和第3個指針都修飾指向的對象,指針對象可變,但所指向的數(shù)據(jù)的值不能變。即,指針可以指向不同的對象,但不能通過指
17、針來修改被指向的值。這種指針也被稱為可變指針。第4個指針,指針本身不能變,但指向?qū)ο蟮闹悼勺儭_@種指針被稱為指針常量。第5種指針的指向不可變,指針的內(nèi)容也不可變。第24頁/共77頁7.4 初 始 化 指針在定義后,僅僅是分配了一個32位的內(nèi)存單元,而沒有對指針進行初始化。如果沒有初始化,那么指針的指向是隨機的、未知的,這叫野指針。如果直接引用野指針,不僅可能破壞程序,而且可能訪問到程序之外。如果使用不當,甚至也會影響到操作系統(tǒng)的安全。這是非常嚴重的事情,因此,指針在使用前必須初始化。對于指針的初始化,有兩種類型: 什么都不指; 內(nèi)存地址。 其中,“什么都不指”指給指針賦予一個值,讓它不指向任何
18、地方,即空指針。這可以通過兩種方法來實現(xiàn),直接給指針賦予數(shù)值0和NULL。數(shù)值0是唯一可以不經(jīng)過轉(zhuǎn)換直接賦給指針的數(shù)值,除此之外的任何數(shù)值都不能直接賦給指針。NULL是宏,與0的效果是一樣的。被賦予這兩個值的指針都表示該指針為空,C+中傾向于使用0來表示空指針。第25頁/共77頁【示例7-7】 指針賦為空。 int *pInt1=0;/賦空值 int *pInt2=NULL; /賦空值 coutpInt1endl;/輸出地址 coutpInt2endl;/輸出地址 cout*pInt1endl;/輸出內(nèi)容 cout*pInt2endl;/輸出內(nèi)容 *pInt1=8;/賦值第26頁/共77頁 分
19、析:該示例定義了兩個整型指針,兩個指針都被初始化為空指針。第3、4語句是直接寫指針的名稱表示輸出指針的地址。由于兩個指針都是空,所以兩個輸出語句的輸出都是0。第5、6兩條語句是輸出指針的內(nèi)容。由于指針為空,所以其內(nèi)容也就為空??罩羔樀牡刂窞?,可以輸出,但空指針的內(nèi)容由于為空,不能被輸出。所以第5、6兩條語句可以被編譯通過,但執(zhí)行時會導致程序出錯,甚至崩潰。最后一條語句是給指針賦值。由于pInt1被初始化為空,即它沒有被分配用來存儲數(shù)據(jù)的內(nèi)存單元,所以對一個空指針賦值也是危險的,同樣會導致程序錯誤。 注意:給指針初始化為空只能保證它不是某個隨意亂指的野指針,不給其分配存儲空間,直接使用空指針是
20、不允許的。第27頁/共77頁 除了將指針初始化為空,還可以將指針初始化為某個特定的地址,這種賦值的方法有多種。第28頁/共77頁7.4.1 用另一個指針的地址初始化 這種方法是指用一個已經(jīng)被初始化過的指針地址來初始化,這意味著它們將指向相同的單元。如果兩個指針類型相同,則可直接賦值;否則,要轉(zhuǎn)換為與被初始化指針相同類型的指針才能賦值。第29頁/共77頁【示例7-8】 設已有字符指針p1,如果p2是char型指針,則直接用p1=p2初始化p1即可。p3是整型指針,故需要強制類型轉(zhuǎn)換。 char *p2=p1;/用已有指針p1給p2賦值 int *p3=(int *)p1;/類型不同的指針間的賦值
21、第30頁/共77頁7.4.2 用某個變量的地址初始化 這種方法是用已經(jīng)定義的變量來初始化指針,要用到取地址運算符&。取地址運算符的用法如下所示。 p=&var; 其中,p是指針,var是變量。賦值后,p將指向var,p的值就是var。這要求兩者具有相同的類型,即指針所指向的類型與var類型相同。否則,就需要執(zhí)行強制類型轉(zhuǎn)換。第31頁/共77頁【示例7-9】 演示用變量的地址初始化指針的方法。 char var; char *p=&var;/取變量的地址給指針p 分析:如果指針的類型與所指內(nèi)容的類型不同,則需要類型轉(zhuǎn)換,如示例7-8中所示。這種類型轉(zhuǎn)換只是對內(nèi)存單元做了重
22、新解釋。因為指針無論什么時候都只是一個無符號整型數(shù),所以指針的強制類型轉(zhuǎn)換的目標實際是上指向的內(nèi)存單元。這種轉(zhuǎn)換只是告訴系統(tǒng)要按指定的格式來解釋某塊內(nèi)存單元的數(shù)據(jù)。例如將指向整型類型的指針強制轉(zhuǎn)換為字符型,表示告訴系統(tǒng)將該指針指向的占4個字節(jié)的整型數(shù)據(jù)解釋為字符型,并且只取sizeof(char)長度的字節(jié)作為字符指針的值。 除非程序員真的能夠很好地控制不同種類型指針之間的強制轉(zhuǎn)換的結(jié)果;否則不鼓勵這么做。這么做也存在導致指針越界,指向非法區(qū)域的危險。第32頁/共77頁7.4.3 用new分配內(nèi)存單元有時定義指針不是為了指向已經(jīng)定義好的其他變量,而是為了開辟新的存儲單元,這時就需要動態(tài)申請內(nèi)存
23、單元。C+采用new運算符來申請新的存儲單元,格式如下。p=new type;或p=new type;其中,p表示指針,new是關鍵字,type是類型名,表示需要n個type類型長度的存儲單元。new返回新分配的內(nèi)存單元的地址。第一種格式表示申請一個type類型長度的內(nèi)存單元,第二種格式表示申請n個type類型長度的內(nèi)存單元。第33頁/共77頁 當申請的內(nèi)存單元不再使用時,必須予以收回,這要用到與new配對的delete運算符。其格式如下所示。 delete p; 或 delete p; 其中,delete是關鍵字,p是指針,表示要刪除new分配的多個type類型的存儲單元。兩種格式分別與ne
24、w的兩種格式相對應。需要注意的是delete并沒有破壞指針p的內(nèi)容,它只是告訴系統(tǒng)收回這片內(nèi)存單元,可以重新利用。所以delete后,最好將p顯示置為空指針。第34頁/共77頁【示例7-10】 演示new/delete的使用方法。 char *p; p=new char;/申請內(nèi)存塊,將地址賦給p *p=a;/修改p所指向的內(nèi)容 delete p;/釋放p所指向的內(nèi)存塊第35頁/共77頁7.4.4 用malloc分配內(nèi)存單元 除了new/delete外,C+中還保留了C中分配動態(tài)內(nèi)存的方法。C中使用malloc/free函數(shù)對來分配和釋放動態(tài)內(nèi)存,這和new/delete比較類似。malloc
25、的原型為: extern void *malloc(unsigned int num_bytes); 該函數(shù)在頭文件malloc.h中,它的功能是申請num_bytes字節(jié)的連續(xù)內(nèi)存塊。如果申請成功則返回該塊的首地址;否則返回空指針NULL。用法如下所示。 type pn; p=(type*)malloc(sizeof(type)*n); 其中,p是type型指針,sizeof(type)是計算一個type型數(shù)據(jù)需要的字節(jié)數(shù),n表示需要存儲n個type型數(shù)據(jù)。(type*)是對malloc的返回值進行強制轉(zhuǎn)換。該式的含義是申請可以存儲n個type型數(shù)據(jù)的內(nèi)存塊,并且將塊的首地址轉(zhuǎn)換為type型
26、賦給p。第36頁/共77頁 當用malloc分配的內(nèi)存不再使用時,應使用free()函數(shù)將內(nèi)存塊釋放。格式如下所示。 free (p); 其中,p是不再使用的指針變量。同delete一樣,free也沒有破壞指針p的內(nèi)容,只是告訴系統(tǒng)收回這片內(nèi)存單元,可以重新利用。所以free后,最好將p顯示置空指針。第37頁/共77頁【示例7-11】 演示malloc/free的使用方法。 p=(char*)malloc(sizeof(char)*2);/申請2個存放char類型數(shù)據(jù)的內(nèi)存塊 free (p);/釋放p指向的內(nèi)存單元 分析:malloc/free與new/delete的區(qū)別在于:前者是C+/C
27、語言的標準庫函數(shù),后者是C+的運算符,是保留字。malloc返回的是無符號指針,需要強制轉(zhuǎn)換才能賦給指針變量,而new可以返回正確的指針。 說明:malloc只是分配要求的內(nèi)存單元,而new則可以自動根據(jù)類型計算需要的內(nèi)存空間。如果有構(gòu)造函數(shù),new還會自動執(zhí)行。第38頁/共77頁【示例7-12】 綜合演示指針的使用方法。 分析:該示例中定義了4個變量,分別采用4種不同的方法初始化。pInt1被初始化為整型變量iVal的地址,因此pInt1的內(nèi)容應該是100。pInt2被直接賦于指針pInt1,兩者將指向同一內(nèi)存單元。pInt3用new運算符申請,Int4用mallocf申請。 其中,0 x2
28、2ff64等數(shù)字是以十六進制表示的地址。第39頁/共77頁7.5 指針的運算 指針變量可以像普通變量一樣進行運算,但其運算的種類是有限的,而且變化規(guī)律要受其所指向類型的制約。一般來講,它只能進行賦值運算、部分算術(shù)運算和關系運算。賦值運算可以參考7.4“初始化”小節(jié),本節(jié)主要講解指針的算術(shù)運算和關系運算。第40頁/共77頁7.5.1 算術(shù)運算 指針只能完成兩種算數(shù)運算:加和減。指針的加減運算與普通變量的加減運算不一樣,指針的加減變化規(guī)律要受所指向的類型約束。它只能與以整型作為基類型的數(shù)據(jù)類型進行運算,或者在指針變量之間。指針的運算都是以元素為單位,每次變化都是移動若干個元素位。 指針的加減運算不
29、是單純的在原地址基礎上加減1,而是加減一個數(shù)據(jù)類型的長度。所以,指針運算中“1”的意義隨數(shù)據(jù)類型的不同而不同。例如指針是整型指針,那么每加減一個1,就表示將指針的地址前或后移動一個整型類型數(shù)據(jù)的長度,即地址要變化4個字節(jié),移動到下一個整型數(shù)據(jù)的首地址上。這時“1”就代表4。如果是double型,那么“1”就代表8。第41頁/共77頁 指針的加減運算最好限定在事先申請的內(nèi)存單元內(nèi),不要通過加減運算跨越到其他內(nèi)存塊內(nèi)。雖然,編譯器不會對這個問題報錯,但這么做是很危險的。有可能在無意識的情況下訪問或破壞了其他內(nèi)存單元的數(shù)據(jù)。 指針可以進行加減運算,但兩指針之間只能進行減運算。兩個指針的減法表示計算它
30、們之間的元素個數(shù)。如果差為負數(shù),表示地址高的指針需要后移幾次才能到地址低的指針處。如果是正數(shù),表示地址低的指針需要移動幾次才能前進到地址高的指針處。這個值實際是指針地址的算術(shù)差除以類型寬度得到的。第42頁/共77頁【示例7-13】 演示指針的加減運算。 分析:該示例定義了兩個指針變量,申請了5個單位的整型存儲單元,分別考察了指針的加減運算和指針間的減運算。首先用new運算符申請了5個單位的整型存儲單元。由于填充存儲單元時,需要移動指針,所以將申請的存儲單元的首地址保留下來,這由語句“pInt2=pInt1;”來完成。接下來用for循環(huán)給每個存儲單元賦值,用“pInt1+;”實現(xiàn)指針的移動,一次
31、一個元素。在for語句內(nèi)還依次輸出了5個存儲單元的首地址。從第04個單元的輸出可以看出,指針的加法是以元素為單位,加1就表示地址要移動sizeof(int)個字節(jié)。 分析循環(huán)語句可知,從循環(huán)退出后指針將移出存儲單元一個元素的長度,因此需要移回來。這用語句“pInt1-;”實現(xiàn)。接下來又按倒序輸出了存儲單元中的內(nèi)容,如輸出中第615行所示。注意到第15個輸出的地址不再存儲單元內(nèi),其原因與前一個循環(huán)一樣,同樣需要移回。第43頁/共77頁 第五步將pInt2后移了四個元素。此時,pInt2在第一個元素上。由于計算機中元素的計數(shù)是從0開始,所以移到第四個元素需對pInt2加3,即移動3次。對照移動前后
32、的地址和第04的輸出可看出,3在這里代表了3*sizeof(int)個字節(jié)。然后對pInt2又移動了一個元素,到了存儲單元的末尾元素上。此時pInt1在首元素上,故兩指針的差為4,表示pInt1需要移動4次才能移到pInt2處。第44頁/共77頁7.5.2 關系運算 指針之間除了可以進行減運算外,還可以進行關系運算。指針的關系運算是比較地址間的關系,這包括兩方面:一方面是判斷指針是否為空,另一方面是比較指針的相對位置。進行關系運算的兩個指針必須具有相同的類型。有相同類型的兩個指針p1和p2,則p1和p2間的關系運算式如下所示。 p1=p2:判斷p1和p2是否指向同一個內(nèi)存地址; p1p2:判斷
33、p1是否處于比p2高的高地址內(nèi)存位置; p1=p2:判斷p1是否處于不低于p2的內(nèi)存位置; p1p2:判斷p1是否處于比p2低的低地址內(nèi)存位置; p1=p2:判斷p1是否處于不高于p2的內(nèi)存位置。第45頁/共77頁 以上5種是判斷兩個指針之間的比較,下面兩種是判斷指針是否為空。 p1=0:判斷p1是否是空指針,即什么都不指; p1=NULL:含義同上; p1!=0:判斷p1是否不是空指針,即指向某個特定地址; p1!=NULL:含義同上。 注意:C+標準中并沒有規(guī)定空指針必須指向內(nèi)存中的什么地方,具體用什么地址值來表示空指針取決于系統(tǒng)的實現(xiàn)。因此,NULL并不總等于0。這就存在了零空指針和非零
34、空指針兩種,但是C+傾向于使用零空指針。 上述4種都是判斷指針與空指針之間的關系,這在通過指針遍歷鏈表、數(shù)組等連續(xù)內(nèi)存單元時很有用,可以作為遍歷終止的條件。第46頁/共77頁【示例7-14】 演示指針的關系運算。 分析:該示例定義了兩個整型指針變量pInt1和pInt2,用new運算符給pInt1分配了可存放5個整型數(shù)據(jù)的內(nèi)存單元。申請時使用了dowhile循環(huán),循環(huán)的出口條件是“pInt1=0”。這表示通過判斷pInt1是否為空,從而判斷是否成功申請到內(nèi)存空間。如果為空,表明申請失敗,繼續(xù)申請,直至申請成功為止。申請成功后,將pInt1的值賦給了pInt2,從輸出結(jié)果可看出,兩者指向了同一個
35、內(nèi)存單元。因此,判等運算輸出為1,判斷pInt1是否地址比pInt2高輸出0。 接下來,pInt2移動了一個位置,從輸出可以看出,地址增加了4個字節(jié),恰是一個int型數(shù)據(jù)的長度。然后再次對pInt1和pInt2判等,顯然兩者不等,故輸出0。但顯然pInt2在比pInt1高的位置上,故下一個比較輸出了1。最后判斷pInt1是否是空指針,輸出0。第47頁/共77頁7.6 指針的指針 指針的指針意味著指針所指向的內(nèi)容仍然是另一個指針變量的地址,這在7.2節(jié)提到過。指針的指針是指針中的難點,不易理解。本節(jié)將向讀者詳細講解它的內(nèi)涵和用途。指針的指針聲明方式如下: type *ptr; 變量訪問內(nèi)存單元是
36、直接訪問,用指針訪問內(nèi)存單元則屬于間接訪問。如果指針直接指向數(shù)據(jù)單元,則稱為單級間址。單級間址定義時使用一個*號。如果指針指向的內(nèi)容依然是地址,該地址才指向真正的數(shù)據(jù)單元,那么這種指針就叫二級間指。二級間指定義時使用兩個*號。第48頁/共77頁【示例7-15】 假設有字符變量ch=a,則讓指針ptr1指向ch,指針ptr2指向ptr1的代碼如下所示。 char ch=a; char *ptr1=&ch; char *ptr2; *ptr2=&ptr1; 分析:指針的指向關系如圖7-4所示。 在該圖中,ch存放在1004單元中,字符變量占一個字節(jié)。ptr1存放在1000開始的4字
37、節(jié)內(nèi)存單元中(指針是無符號整型數(shù),占4字節(jié)),它的內(nèi)容是ch所在單元地址1004。ptr2放在1006開始的4字節(jié)中,其內(nèi)容是ptr1所在的內(nèi)存塊的首地址。它們之間的指向關系如圖中的箭頭所示。第49頁/共77頁圖7-4 單級間指與二級間指 從圖7-4可見,如果用ptr1去訪問能ch,則只需要一次跳轉(zhuǎn)就可尋址到ch。而如果通過ptr2來訪問ch,則需要先跳轉(zhuǎn)到ptr1,再跳轉(zhuǎn)到ch。 定義中有幾個*號就是幾級間指,訪問到最終數(shù)據(jù)單元時就需要幾級跳轉(zhuǎn)。第50頁/共77頁【示例7-16】 多級間指舉例。 int *p;/三級間指 int *p;/四級間指 分析:理解間指時要從右向左。對于“int *
38、p;”可按如下過程理解。從右向左,先看到p,表明變量名為p。再向左,遇到*,表明p的內(nèi)容是地址,*p是指針。繼續(xù)向左,又是*,表明*p的內(nèi)容是地址,*p是指針。再向左,還是*,表明*p內(nèi)容依然是地址,*p是指針。最后再向左是int,沒有了*,表明*p的內(nèi)容是整型數(shù)據(jù)。 技巧:將指針的指針用于數(shù)組和函數(shù)傳值中。指針的指針常常作為函數(shù)的參數(shù),使函數(shù)能夠修改局部指針變量,即在函數(shù)內(nèi)修改局部指針的指向。在數(shù)組處理中,可以用指針的指針來代替多維數(shù)組。第51頁/共77頁7.7 指針的使用 指針與其他變量一樣,必須先定義后使用,而且必須先初始化。否則,指針就是一個野指針,使用這樣的野指針會造成不可預期的后果
39、。本章7.4節(jié)中詳細討論了指針初始化的問題,這一節(jié)就來討論一下指針使用方面的問題,這包括兩方面:賦值和取內(nèi)容。第52頁/共77頁7.7.1 指針的賦值 在7.4節(jié)講過指針的初始化,賦值與初始化基本類似,7.4節(jié)談到的初始化方法都適用于賦值。但兩者也有一些細微的差別。初始化多發(fā)生在定義時,而賦值則多在定義以后。初始化時如果不是字符串,則右值只能使用地址。因為,此時指針還沒有指向特定的內(nèi)存單元,所以不能給它賦數(shù)據(jù)。字符串實質(zhì)是字符數(shù)組,字符數(shù)組是天生的指針。系統(tǒng)會自動為字符串分配存儲單元,并且數(shù)組的名字就是字符串的首地址指針。此時實質(zhì)還是地址。賦值可以賦地址或數(shù)據(jù),第53頁/共77頁 格式如下所示
40、。 p1=&var; p1=p2; *p1=var; 第1個式子中,p1是指針變量,var是變量。&是取地址運算符(格式參7.4節(jié)),取出變量var的地址。所以,第1個式子表示讓指針指向變量var。第2個式子中p1和p2是同類型的指針,表示讓p1指向p2所指的內(nèi)存單元。第3個式子中,p1是指針變量,var是變量。*是間接操作符,表示間接訪問p1指向的內(nèi)存單元。該式表示直接用變量var來修改指針所指向的內(nèi)存單元的內(nèi)容。賦值時,若左值不帶*,則只能賦予地址;否則只能賦予指針變量的內(nèi)容。第54頁/共77頁【示例7-17】 演示指針的賦值方法。 分析:該示例中指針變量p1、p2的初始化
41、和賦值是一樣的過程,而p3則是先初始化,再賦值。賦給p1的是變量iVal的地址,由取地址運算符取出。賦給p2的則是p1的指針,p2和p1將都指向變量iVal。p3則是先初始化為空指針,再用new申請存儲單元,然后再賦值。通過間接訪問,將100保存到p3中。 注意:賦地址時,不要求左值原來必須指向某個內(nèi)存單元。而賦數(shù)據(jù)則要求指針必須指向某個內(nèi)存單元,給其賦值只是填充了該內(nèi)存單元的內(nèi)容。第55頁/共77頁7.7.2 *操作符 *操作符也叫間接訪問運算符,用來表示指針所指的變量,結(jié)合性為從右到左,屬于單目運算。*運算符后跟的必須是指針變量。如果作為左值,則是向指針所指單元中寫入數(shù)據(jù)。如果作為右值,則
42、是從指針所指單元中讀數(shù)據(jù)。格式如下所示。 *p=常量; *p=var; var=*p; 第1個式子是直接將常量送入p所指的單元。第2個式子是將變量var的值送入p所指向的單元內(nèi)。第3個是將指針p所指單元的數(shù)據(jù)讀出賦給var。第56頁/共77頁【示例7-18】 *操作符的使用方法。 注意:指針運算符*和間接訪問運算符*不同。前者是類型說明符,表示其后的變量是無符號整數(shù),保存的是地址,一次訪問sizeof(type)長度。后者表示間接訪問指針所指的單元,用于賦值或取內(nèi)容。第57頁/共77頁7.8 引用與指針 引用就是別名或同義詞,它是同一塊內(nèi)存單元的不同名稱。常用于替代傳值方式,傳遞參數(shù)和返回值。
43、具有指針的特點,可節(jié)省內(nèi)存復制帶來的開銷。它的定義格式如下所示。 type &ref=var; 其中,type是類型名稱,&是引用的說明符,ref是引用的名稱,var是與引用同類型的變量名稱。該式表示定義一個引用,該引用是var的別名,與var使用同樣的內(nèi)存單元。引用與指針的區(qū)別是: (1)引用只是變量的別名,不開辟新的空間,與原變量使用同一塊內(nèi)存單元。指針則是一個新的變量,有自己的存儲空間。第58頁/共77頁【示例7-19】 測試引用與變量是否使用同一塊內(nèi)存單元。 分析:該示例中,ref引用了x,指針p1指向x,p2指向ref。 從輸出可以看出,變量x和其引用ref使用的內(nèi)存
44、單元是一樣的。而且最后一條語句的輸出也表明ref與x是一樣的,p2和p1都指向x。第59頁/共77頁 (2)引用必須在聲明時就初始化,指針則可在任何時候初始化。例如示例7-19中,如果希望ref引用變量x,就必須在定義ref時用語句int &ref=x實現(xiàn),而不能聲明后,再用“ref=x”或其他形式實現(xiàn)。ref=x這種形式是在給引用賦值,但此時ref還沒有引用任何變量,因此給其賦值是不合邏輯的。實際上,如果引用在定義時懸空,編譯器將報錯。 (3)引用不能為空,必須總是引用一個對象。而指針則可以為空,不指向任何地方。第60頁/共77頁【示例7-20】 給引用和指針賦空。 int &
45、;ref=NULL; *p=NULL; 分析:其中,語句int &ref=NULL是不允許的。而int *p=NULL是允許的,表示p什么都不指。第61頁/共77頁 (4)引用一旦被初始化,就不能再引用其他對象。而指針如果沒有用const修飾,就可以重新指向不同的變量。例如示例7-19中,ref=x這樣的語句只能在初始化時出現(xiàn)。因此,即使想改變引用的對象,也不會有機會去實現(xiàn)。 (5)如果引用被const修飾,則可以直接在初始化時賦常量。而指針除了0以外,什么時候都不能直接賦未經(jīng)轉(zhuǎn)換的常量。此時,引用的語義是創(chuàng)建一個臨時的對象,并用該常量來初始化,然后對其引用,直到銷毀引用才銷毀該臨時對
46、象。而指針則意味著直接賦予一個地址,這是不允許的。第62頁/共77頁【示例7-21】 用常量給引用賦值。 分析:該示例中,引用ref2直接賦值為0,這表示創(chuàng)建一個臨時整型對象0,并用ref2引用它,其值為0。而p被賦為0,表示將p初始化為空。 需要注意的是,如果沒有用const修飾引用,則不能直接賦常量。第63頁/共77頁 (6)引用聲明時用&作為標識,使用時像變量一樣直接使用。而指針則用*作為標識,使用時也要用*間接訪問。 (7)sizeof操作施加到引用上時,測試的是被引用對象的寬度。而用于指針時,則是測試指針本身的寬度(同一種機型上,它總是定值)。第64頁/共77頁【示例7-22
47、】 測試了引用型變量和指針型變量在sizeof運算符下的不同。 分析:該示例分別定義了兩種類型的變量、引用和指針,并分別輸出其所占的字節(jié)數(shù)。從輸出中可以看出,兩個引用變量中與其被引用對象占據(jù)相同的字節(jié)數(shù)。這是因為兩者實際上就是使用同一內(nèi)存單元。兩個指針則與被指對象無關,總是4。這是因為32位機型上,指針的占4字節(jié)存儲單元。第65頁/共77頁 引用與指針的共同點: 引用的本質(zhì)也是指針,但是編譯器在編譯階段進行了轉(zhuǎn)換。 指針與引用都是間接引用其他對象。指針是通過地址間接訪問指向的對象,引用是用別名去直接訪問被引用對象。 技巧:當不能決定是選擇指針還是選擇引用時,可以簡單地參照下述兩條原則:若指向沒有命名的對象,或不想指向同一個對象,則使用指針;若總是指向同一個對象,則使用引用。第66頁/共77頁7.9 特 殊 指 針 除了有明確指向和類型的指針外,有時候還常常用到一些特殊類型的指針,以應對特殊的用途。本節(jié)將向讀者介紹void型指針和空指針,這兩種指針在實際應用中經(jīng)常會用到。第67頁/共77頁7.9.1 void型指針 void型指針就是無類型指針。它沒有類型,只是指向一塊申請好的內(nèi)存單元。其格式如下所示。 void *
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度旅游車輛租賃與保障服務合同2篇
- 二零二五年度排水工程環(huán)保驗收合同2篇
- 2025年度私人老板與心理咨詢師專項勞動合同
- 2025年度財稅代理與財務報表編制服務合同
- 2025年度商鋪租賃合同范本全新定制版11篇
- 二零二五年度喜劇電影演員出演合同約定
- 二零二五年度中央空調(diào)拆裝與節(jié)能技術(shù)改造合同
- 2025年度砂石場生產(chǎn)承包與礦山資源合理開發(fā)合同
- 2025年度離婚房產(chǎn)贈與合同附帶配偶撫養(yǎng)子女責任協(xié)議
- 2025年度醫(yī)療設備采購合同解除書
- 結(jié)婚函調(diào)報告表
- SYT 6968-2021 油氣輸送管道工程水平定向鉆穿越設計規(guī)范-PDF解密
- 冷庫制冷負荷計算表
- 肩袖損傷護理查房
- 設備運維管理安全規(guī)范標準
- 辦文辦會辦事實務課件
- 大學宿舍人際關系
- 2023光明小升初(語文)試卷
- GB/T 14600-2009電子工業(yè)用氣體氧化亞氮
- 申請使用物業(yè)專項維修資金征求業(yè)主意見表
- 房屋買賣合同簡單范本 房屋買賣合同簡易范本
評論
0/150
提交評論