第6章指針與字符串_第1頁
第6章指針與字符串_第2頁
第6章指針與字符串_第3頁
第6章指針與字符串_第4頁
第6章指針與字符串_第5頁
已閱讀5頁,還剩168頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、第6章 指針與字符串 第第6 6章章 指針與字符串指針與字符串 6.1 指針的概念指針的概念 6.2 指針型變量指針型變量 6.3 指針與數(shù)組指針與數(shù)組 6.4 指針與函數(shù)指針與函數(shù) 6.5 指針與類、對象指針與類、對象 6.7 動態(tài)內(nèi)存分配與動態(tài)內(nèi)存分配與new和和delete運算符運算符 6.8 string類類 第6章 指針與字符串 6.1 指針的概念指針的概念 指針既是C+語言學(xué)習(xí)中的難點又是重點,要掌握C+語言的精髓,必須學(xué)會熟練使用指針。本節(jié)先引入指針的概念。 為了說明什么是指針,必須弄清楚數(shù)據(jù)在內(nèi)存中是如何存儲的,又是如何讀取的。如果在程序中定義了一個變量,在編譯時就給這個變量分

2、配內(nèi)存單元。 第6章 指針與字符串 系統(tǒng)根據(jù)程序中定義的變量類型,分配一定長度的空間。例如,許多計算機系統(tǒng)對整型變量分配兩個字節(jié),對實型變量分配四個字節(jié),對字符型變量分配一個字節(jié),。內(nèi)存區(qū)的每一個字節(jié)(即單元)有一個編號,這就是“地址”,它相當(dāng)于旅館中的房間號。在地址所標識的單元中存放數(shù)據(jù),這相當(dāng)于旅館中各個房間中住旅客一樣。第6章 指針與字符串 在此,務(wù)必弄清楚一個內(nèi)存單元的地址與內(nèi)存單元的內(nèi)容這兩個概念的區(qū)別。如圖6-1所示,假設(shè)程序已定義了三個整型變量i、j、k,編譯時系統(tǒng)分配2000和2001兩個字節(jié)給變量i,2002、2003字節(jié)給j,2004、2005給k。在內(nèi)存中已沒有i、j、k

3、這些變量名了,對變量值的存取都是通過地址進行的。 第6章 指針與字符串 圖6-1 內(nèi)存單元分配示意 第6章 指針與字符串 還可以采用另一種稱之為“間接訪問”的方式。這類似于在程序中定義整型、實型、字符等變量,也可以定義這樣一種特殊的變量,它是用來存放地址的,即可以將變量i的地址存放在另一個內(nèi)存單元中。假設(shè)我們定義了變量i_pointer是存放整型變量的地址的,它被分配為3030、3031字節(jié)單元??梢酝ㄟ^下面的語句將i的地址存放到i_pointer中: i_pointer=&i; 這時,i_pointer的值就是2000,即變量i所占用單元的起始地址。 第6章 指針與字符串 要存取變量

4、i的值,也可以采用間接方式:先找到存放“i的地址”的單元地址(3030、3031),從中獲得i的起始地址(2000),然后從2000、2001字節(jié)中取出i的值(3)。 簡而言之,指針就是指向內(nèi)存中某個單元的地址值。所有的變量、數(shù)組、對象都是保存在內(nèi)存中的。凡是保存在內(nèi)存中的信息,必須知道它在內(nèi)存中的位置。在計算機中,引用了“地址”這個詞來代表內(nèi)存的某個位置。內(nèi)存以字節(jié)為單位編址,稱為內(nèi)存地址。第6章 指針與字符串 6.2 指針型變量指針型變量 6.2.1指針型變量的聲明 在C+語言中,任何一種數(shù)據(jù)類型都有對應(yīng)的指針類型,甚至指針類型本身也有指針類型。要聲明一種數(shù)據(jù)類型的指針型變量,必須在聲明變

5、量時將“*”號加在數(shù)據(jù)類型的后面。定義指針變量的一般形式如下: *指針變量名第6章 指針與字符串 定義中的“*”表示所定義的變量是一個指針變量,以示與其它變量的區(qū)別。指針變量名的命名應(yīng)符合標識符的命名規(guī)則。指針變量的值是另一變量的指針(即首地址)。定義中的數(shù)據(jù)類型是指針變量所指變量的數(shù)據(jù)類型。 注意,一個指針變量只能指向定義所指定數(shù)據(jù)類型的變量,即存放定義所指定數(shù)據(jù)類型的變量的地址,因此,指針變量所存放的地址是一個具有指定數(shù)據(jù)類型的地址。例如: 第6章 指針與字符串 int*pnNumber;/pnNumber是用來保存一個指向int型變量的指針的指針型變量f1oad*pfRealNumber

6、; /pfRealNumber是用來保存一個指向float型變量的指針的指針型變量BOOL*pbResult;/pbResult是保存一個指向int型變量的指針的指針型變量,注意BOOL型 /與int型的共用特性第6章 指針與字符串 char*ppBuffer5;/數(shù)組ppBuffer是用來保存5個指向char型變量的指針的指針型變量數(shù)組void*pAddress;/pAddress是一個保存內(nèi)存地址的指針型變量,該內(nèi)存地址中保存的數(shù)據(jù) /類型無須知道 void*型指針是很特殊的一種指針,它不像int*、float*等指針那樣,指向的內(nèi)存單元中保存的是具體的一種數(shù)據(jù)類型的變量,void*只是一

7、個地址,這個地址中保存的可能是int型變量的起始地址,也可能是f1oat型變量的起始地址,也可能什么都不是。第6章 指針與字符串 聲明指針型變量時,“*”前后可以加空格,也可以不加,這完全取決于程序員的習(xí)慣。 盡管大多數(shù)指針變量類型同其對應(yīng)的普通數(shù)據(jù)類型之間表面上只差一個“*”號,但它們之間的關(guān)系相當(dāng)特殊。必須牢記這樣的事實:指針型變量也是變量,指針型變量保存的是地址值,這個值實際上就是一個有特殊意義的整數(shù),稱為指針。 C+語言中定義了一個符號常數(shù)NULL,用來代表空指針值。所謂空指針值是人為規(guī)定的一個數(shù)值,用來表示“無效”的指針值。在VisualC+中,NULL被定義為0。 第6章 指針與字

8、符串 6.2.2 指針的基本操作 與指針有關(guān)的基本運算符有以下兩個。 (1)&變量名?!?amp;”為取地址運算符,用來獲取變量的首地址。 (2)*指針變量名。“*”為指向運算符,用來獲取指針變量所指向變量的值。 “&和“*”運算符都是單目運算符,其優(yōu)先級高于所有雙目運算符,采用從右到左的結(jié)合性。第6章 指針與字符串 例如:inti=5,j,*phint; /定義整型變量i、j;同時定義整型指針變量phintphint=&i:/將i的指針(即首地址)賦給phint,使phnti指向ij=*phint;/將phint所指變量i的值(5)賦給變量j第6章 指針與字符串 說明

9、: 指針變量是有類型的。要使指針變量phint存放整型變量i的地址,phint也必須定義為整型指針變量,否則編譯時將出錯。 要注意第1句和第3句中*phint的區(qū)別:第1句是指針變量定義語句,其中的“*”表示phint是一個指針類型變量;第3句中的“*”表示取出指針變量phint的值(即phint所指內(nèi)存單元中的內(nèi)容)。第6章 指針與字符串 6.2.3 指針變量的初始化與引用 與其它變量一樣,指針變量也可以在定義時對其賦初值(即指針變量的初始化)。這里要注意的是,所賦的初值必須是所定義數(shù)據(jù)類型的變量地址。對于上面的程序片段,我們也可以用以下兩句來實現(xiàn): inti=5,j,*phint=&

10、;i;/用整型變量i的首地址初始化整型指針變量phint j=*phint;第6章 指針與字符串 在此還是要強調(diào),指針變量定義語句中的“*”只是一個標志,并沒有間接存取內(nèi)容的含義,不能把int*phint=&i;理解為將i的地址賦給phint所指的內(nèi)存單元,而應(yīng)理解為將i的地址賦給phint本身。 除void*型指針變量以外,其它指針型變量可以通過在變量名前加“*”號的方法訪問該變量所指向的內(nèi)存地址中所保存的相應(yīng)數(shù)據(jù)類型變量的值。 第6章 指針與字符串 【例6-1】指針變量的使用例題。#includevoidmain()intm,n,*p1=&m,*p2=&n,*phi

11、nt=NULL;m=n=6;cout*p1=*p1,*p2=*p2endl;coutp1=p1,p2=p2endl;coutm=m,n=nendl;coutphint=phintendl;第6章 指針與字符串 *p1+=3;p2=p1;*p2*=4;phint=p2;cout*p1=*p1,*p2=*p2endl;coutp1=p1,p2=p2endl;coutm=m,n=nendl;coutphint=phint、=、=、!=可以用來連接兩個指針型變量做關(guān)系運算。指針間的關(guān)系運算結(jié)果就是兩個指針所指的地址值的大小的關(guān)系運算結(jié)果。由于內(nèi)存地址是線性編碼的,所以,如果一個變量m的保存位置在變量n

12、之前,則&m&n就等于0。兩個進行關(guān)系運算的指針一般要求是同一類型的指針。第6章 指針與字符串 4常指針(const修飾符與指針) 與#define語句相比較,C+提供了一種更靈活、更安全的方式來定義常量,即使用const修飾符來定義常量。例如: constintLIMIT=100; 它類似于#defineLIMIT100;語句,但此時這個常量是類型化的,它有自身的地址。 const也可以與指針一起使用。它們的組合情況較復(fù)雜,可簡單歸納為三種:指向常量的指針、常指針和指向常量的常指針。第6章 指針與字符串 (1)指向常量的指針。指向常量的指針是指一個指向常量的指針變量。例如:c

13、onstchar*name=chen;/聲明指向字符常量的指針變量 這個語句的含義是:聲明一個名為name的指針變量,它指向一個字符型常量,初始化name為指向字符串chen。 由于使用了const,不容許改變指針所指的常量,因此以下語句是錯誤的: name3=a;/即name所指的數(shù)據(jù)不可修改 但是,由于name是一個指向常量的普通指針變量,不是常指針,因此可以改變name的值。 第6章 指針與字符串 (2)常指針。常指針是指把指針本身,而不是它指向的對象聲明為常量。例如: char*constname=chen;/常指針 這個語句的含義是:聲明一個名為name的指針,該指針是指向字符型數(shù)據(jù)

14、的常指針,用chen的地址初始化該常指針。創(chuàng)建一個常指針,就是創(chuàng)建一個不能移動的固定指針,但是它所指的數(shù)據(jù)可以改變。例如: name3=a/合法 name=zhang;/出錯 第一個語句改變了常指針所指的數(shù)據(jù),這是允許的;但第二個語句要改變指針本身,這是不允許的。第6章 指針與字符串 (3)指向常量的常指針。指向常量的常指針是指這個指針本身不能改變,它所指向的數(shù)據(jù)值也不能改變。要聲明一個指向常量的常指針,二者都要用const修飾。例如: constchar*constname=chen; /指向常量的常指針 這個語句的含義是:聲明了一個名為name的指針,它是一個指向字符型常量的常指針,用ch

15、en的地址初始化該指針。不難理解以下兩個語句都是錯誤的: name3=a;/出錯,不能改變指針所指的值 name=zhang;/出錯,不能改變指針本身第6章 指針與字符串 5引用型變量 引用型變量是從指針型變量發(fā)展來的一種特殊類型的變量。引用變量的實質(zhì)仍然是指針,但采用了不同于指針的表示方法,可以簡化對函數(shù)有多個返回值時的處理,使得程序更加清晰可讀。 引用型變量是C+的新增特性,是一種不具備自己的實際數(shù)據(jù)存儲空間的變量,它必須與另一個同類型的變量共用一個空間。換句話說,它只是另一個目標對象的別名,其本身不是一個獨立的變量。因此,引用只有聲明,沒有定義。第6章 指針與字符串 【例6-2】引用的聲

16、明和使用例題。#includevoidmain()inti,j=4,&ri=i;/定義ri為整型變量i的引用i=3;couti=i,ri=riendl;couti的地址是&i,ri的地址是&riendl; 第6章 指針與字符串 ri+=5;couti=i,ri=riendl;couti的地址是&i,ri的地址是&riendl;ri=j;couti=i,ri=ri,j=jendl;couti的地址是&i,ri的地址是&ri,j的地址是&jendl;ri=&j;/出錯第6章 指針與字符串 刪除最后一句出錯的語句后,程序的運行結(jié)

17、果為i=3,ri=3i的地址是0 x0012FF7C,ri的地址是0 x0012FF7Ci=8,ri=8i的地址是0 x0012FF7C,ri的地址是0 x0012FF7Ci=4,ri=4,j=4i的地址是0 x0012FF7C,ri的地址是0 x0012FF7C,j的地址是0 x0012DD78第6章 指針與字符串 這個例子清楚地表明:引用ri與它的目標變量i具有相同的內(nèi)存地址,它們的值是同步變化的,即使引用ri被重新賦予變量j的值,ri的值發(fā)生改變(i的值也隨之改變),但ri仍以i作為自己的目標,仍以i的地址作為自己的地址,這一點不會改變。 第6章 指針與字符串 6.3 指針與數(shù)組指針與數(shù)

18、組 6.3.1 指針與數(shù)組的關(guān)系 數(shù)組的實質(zhì)是內(nèi)存中一塊連續(xù)的空間,存儲著同一類型變量的數(shù)據(jù)。要訪問數(shù)組中的某個元素,可以通過“數(shù)組名下標”這樣的語法形式來實現(xiàn)。其中,下標是要被訪問的元素在數(shù)組中的位置。由此,不難得出這樣的結(jié)論:如果知道數(shù)組第1個(下標為0)元素的地址,將這個地址保存在某個指針變量中,那么對數(shù)組元素的訪問就完全可以轉(zhuǎn)換為指針操作。 第6章 指針與字符串 例如,已知指針型變量int*pnPointer中保存了數(shù)組intpnArray10的第1個元素的地址,則通過對指針變量pnPointer加上一個整數(shù),就可以訪問數(shù)組pnArray中的任何一個元素,即,pnArrayn與*(pn

19、Pointer+n)是等同的。第6章 指針與字符串 實際上,C+語言就是這樣對數(shù)組元素進行訪問的。在聲明一個數(shù)組時,C+語言將在內(nèi)存中開辟兩個空間,一個用于保存數(shù)組元素,另一個用于保存數(shù)組的第1個元素的地址。數(shù)組名就是用于保存數(shù)組第1個元素的地址的指針型常量。通過保存數(shù)組第1個元素地址的數(shù)組名這個指針型常量,可以使用“”運算符訪問數(shù)組元素,也可以直接使用指針的運算規(guī)則訪問數(shù)組元素。 第6章 指針與字符串 intpnArray10;intnValue;nValue=*pnArray;/nValue等于prlArray的第1個元素的值nValue=pnArray5;/nValue等于pnArray

20、的第6個元素的值nValue=*(pnArray+5);/與上一句nValue=pnArray5;等價同樣,對于指針型變量也可以使用“”運算符,將其作為數(shù)組來使用。如有int*pnPointer=pnArray;/數(shù)組名pnArray本身是指針型,因此不必用取地址運算符&第6章 指針與字符串 則以下三條語句等價:nValue=pnArray5;nValue=pnPointer5;nValue=*(pnPointer+5);盡管指針與數(shù)組之間有著密切的聯(lián)系,但也有區(qū)別。 第6章 指針與字符串 指針型變量是變量,是可以不斷賦值的;而數(shù)組名雖然是指針,但它是一指針型常量,只能指向固定的內(nèi)存地

21、址,不能將一個指針值賦予一個數(shù)組名。以下語句在C+語言中是錯誤的: charcArray10; charch; cArray=&ch; /錯誤,不允許將一個指針值賦予數(shù)組名第6章 指針與字符串 6.3.2 通過指針引用數(shù)組元素 由于指針同數(shù)組的特殊關(guān)系,我們已經(jīng)看到,數(shù)組與指針幾乎可以互換使用。下面利用一個具體例子來說明通過指針引用數(shù)組元素的方法。 【例6-3】用指針的方法編寫求一個數(shù)組中所有元素之和的程序。 分析:此函數(shù)的參數(shù)可以寫成指針型。由于數(shù)組名的實質(zhì)就是指針,在調(diào)用該函數(shù)時,只要將數(shù)組名作為實際參數(shù)傳遞給函數(shù)即可。程序代碼如下: 第6章 指針與字符串 #includeintS

22、um(int*pPointer,intn)intnSum=0;while(n0)nSum+=*pPointer;pPointer+;n-;第6章 指針與字符串 returnnSum;voidmain()intpnArray10=6,7,8,9,5,4,3,2,10,1;intsumArray;sumArray=Sum(pnArray,10);cout數(shù)組各元素和:sum1=sumArrayendl;程序運行結(jié)果為數(shù)組各元素之和:sum1=55第6章 指針與字符串 【例6-4】對上例6-3,用指針的方法編寫將數(shù)組各元素進行排序的函數(shù)程序。分析:參照例3-5,用選擇法進行排序(降序)。#inclu

23、devoidSum(int*pPointer,intn)inti,j,t,p;for(i=0;in-1;i+)p=i;for(j=i+1;jn;j+)第6章 指針與字符串 if(*(pPointer+p)=*(pPointer+j)p=j;t=*(pPointer+i);*(pPointer+i)=*(pPointer+p);*(pPointer+p)=t;voidmain()第6章 指針與字符串 intpnArray10=6,7,8,9,5,4,3,2,10,1;inti;Sum(pnArray,10);cout排序后的數(shù)組為:endl;for(i=0;i10;i+)coutpnArrayi

24、endl;程序運行結(jié)果為排序后的數(shù)組如下:10,9,8,7,6,5,4,3,2,1第6章 指針與字符串 6.3.3 指向多維數(shù)組的指針 多維數(shù)組的元素在計算機中同一維數(shù)組的元素一樣,是線性存儲的。只要知道保存某個多維數(shù)組的內(nèi)存區(qū)域的首地址,就可以通過指針訪問多維數(shù)組中的任何一個元素。 以二維數(shù)組intfMatrix34為例。它的首地址應(yīng)該是&fMatrix00,如果將這個地址值賦予指針型變量int*pPointer,則二維數(shù)組fMatrix中的任何一個元素使用 p P o i n t e r 這 個 指 針 來 訪 問 的 規(guī) 則 是 :*(pPointer+m*4+n)等同于fMat

25、rixmn。其中,4是二維數(shù)組的列長度。第6章 指針與字符串 這是因為對于多維數(shù)組,C+語言采用按行順序保存的規(guī)則(列標優(yōu)先變化)。對二維數(shù)組fMatrix而言,在保存fMatrix的存儲區(qū)中排在前面的是第1行fMatrix00到fMatrix03這4個元素,然后是第2行fMatrix10到fMatrix13這4個元素,最后是第3行fMatrix20到fMatrix23這4個元素。 多維數(shù)組的數(shù)組名同樣是個指針,但它不指向多維數(shù)組的最前一個被保存的元素的地址(&fMatrix00),它指向的是存放下一維元素的首地址指針所在的地址。對于初學(xué)者來說,這很難理解。仍以上述中的fMatrix數(shù)

26、組來說明這個問題。第6章 指針與字符串 對二維數(shù)組fMatrix34中關(guān)于一維數(shù)組名fMatrixm(0m3)所代表的含義,我們已在第3章多維數(shù)組中進行過討論。如果把fMatrixm當(dāng)成一個一維數(shù)組的數(shù)組名,則將fMatrixm加上下標,就可以訪問一維數(shù)組fMatrixm中的各元素了,即將二維數(shù)組fMatrix看成了3個一維數(shù)組。不難發(fā)現(xiàn),這是一個保存了3個指向一維數(shù)組的指針的數(shù)組。也就是說,此時一維數(shù)組fMatrix中數(shù)組元素的數(shù)據(jù)類型是指針類型,其數(shù)組元素fMatrixm保存的是下一維數(shù)組的第1個元素的首地址(&fMatrixm0)。 第6章 指針與字符串 于是,就有fMatrix

27、0等于&fMatrix00fMatrix1等于&fMatrix10fMatrix2等于&fMatrix20最后,再來看fMatrix的含義。 第6章 指針與字符串 【例6-5】用指針的方法將二維數(shù)組的轉(zhuǎn)置(行列互換)形式輸出,并輸出相應(yīng)的指針值,進行觀察、比較。 #include voidmain() intaMatrix34=1,2,3,4,5,6,7,8,9,10,11,12; inti,j,*p; cout轉(zhuǎn)置前的矩陣:endl; for(i=0;i3;i+) 第6章 指針與字符串 p=aMatrixi;/p存放各行的起始地址for(j=0;j4;j+)cout*

28、(p+j);coutendl;cout轉(zhuǎn)置后的矩陣:endl;for(j=0;j4;j+)for(i=0;i3;i+)p=aMatrixi;/p存放各行的起始地址(注意所在的位置) 第6章 指針與字符串 cout*(p+j);coutendl;cout輸出相應(yīng)的指針值:endl;coutaMatrixaMatrix0&aMatrix00endl;for(i=0;i3;i+)coutaMatrixi&aMatrixi0endl;程序運行結(jié)果為第6章 指針與字符串 轉(zhuǎn)置前的矩陣:123456789101112轉(zhuǎn)置后的矩陣:159261037114812第6章 指針與字符串 輸出相應(yīng)

29、的指針值(以下地址值根據(jù)系統(tǒng)運行情況而定): 0 x0012FF500 x0012FF500 x0012FF50 0 x0012FF500 x0012FF50 0 x0012FF600 x0012FF60 0 x0012FF700 x0012FF70第6章 指針與字符串 6.3.4 指針數(shù)組與多級指針 1指針數(shù)組 同一般數(shù)組一樣,多個類型相同的指針變量也可以依數(shù)組的形式進行表示。聲明指針型變量數(shù)組的形式同聲明普通數(shù)組一樣,只不過類型是指針類型。聲明指針型變量的形式 如下: *指針數(shù)組名數(shù)組長度第6章 指針與字符串 例如: int*ppArray5;/聲明一個保存5個int*型元素的指針數(shù)組 c

30、har*ppString6;/聲明一個保存6個char*型元素的指針數(shù)組 指針型變量的數(shù)組中每個元素都是指針,同普通數(shù)組一樣,這些指針按順序保存在內(nèi)存的某個空間中,數(shù)組名就是指向這個空間首地址的指針。 由于指針數(shù)組中每個元素都是指針,那么從指針數(shù)組中取出的元素就具有指針的全部性質(zhì)。例如,*(ppString0)代表數(shù)組元素ppString0所指向的單元(保存的地址值)。第6章 指針與字符串 2多級指針 多級指針一般又稱為指針的指針。 如前所述,指針變量的內(nèi)容是某種數(shù)據(jù)類型的地址,當(dāng)然也包括指針類型的地址。一個指針型變量保存的是另一個指針型變量的地址,則這個指針型變量就是指針的指針。指針的指針類

31、型的表示法是在原先的指針類型后再加一個“*”號。由于多級指針比較復(fù)雜,在此我們只以二級指針為例進行介紹。第6章 指針與字符串 定義二級指針變量的一般形式如下: *二級指針變量名 當(dāng)一個指針變量(如pp)的內(nèi)容是另一個指針變量(如p是一個指向非指針類型的基本數(shù)據(jù)類型,稱為一級指針)的地址(稱為pp指向p)時,pp就是二級指針變量,或稱為指向指針的指針變量。圖6-4說明了一級指針變量p與二級指針變量pp之間的區(qū)別和聯(lián)系。 第6章 指針與字符串 第6章 指針與字符串 顯然,如果我們希望通過二級指針變量pp來訪問整型變量I,必須經(jīng)過兩次間接尋址。先由pp取出它所指的內(nèi)容(p的地址),即*pp,再由*p

32、p(即i的地址)取出變量i的值,即*pp,這里要兩次使用取內(nèi)容運算符“*”。所以,i的值也可有*pp與*p兩種形式表示。 另外,由此可進一步理解二維數(shù)組名是一個二級指針的含義,實質(zhì)是指向一維指針數(shù)組第1個元素(下標為0)的指針型常量。第6章 指針與字符串 例如,對上例6-5,若定義二級指針變量 int*pp; 則pp=aMatrix;是合法的,且*pp、*aMatrix、*aMatrix0都可表示元素aMatrix00 的值。 指針的指針對初學(xué)者來說是個不易接受的概念,但只要明確以下兩點,所有的問題都會迎刃而解: 指針的指針仍然是變量。 指針的指針仍然是指針型變量,只不過保存的地址指向的內(nèi)存單

33、元中保存的還是一個指針。 第6章 指針與字符串 6.4 指針與函數(shù)指針與函數(shù) 6.4.1 指針變量作為函數(shù)參數(shù) 指針類型也可以作為函數(shù)的參數(shù)。通過指針型參數(shù),可以將一個變量的地址傳遞給函數(shù),而通過這個地址,函數(shù)體中的語句就可以修改函數(shù)以外的變量的值。為了使大家能夠?qū)ζ胀ㄗ兞孔鳛楹瘮?shù)參數(shù)與指針變量作為函數(shù)參數(shù)深入理解,下面我們以這兩種不同的參數(shù)傳遞方式舉例,以進行對比說明。第6章 指針與字符串 (1)數(shù)值傳遞。所謂數(shù)值傳遞,即普通變量作為函數(shù)參數(shù)。主調(diào)函數(shù)中的實參內(nèi)容是一個數(shù)值,其特點是,形參改變,實參不變。 【例6-6】通過函數(shù)調(diào)用交換兩個變量的值。 #include voidchangFun

34、ction(int,int);/函數(shù)聲明語句 voidmain() 第6章 指針與字符串 inta=5,b=10;cout函數(shù)調(diào)用前:a=a,b=bendl;changFunction(a,b);/以a、b的值為實參調(diào)用函數(shù)cout函數(shù)調(diào)用后:a=a,b=bendl;voidchangFunction(intm,intn)inttemp;temp=m;m=n;n=temp;第6章 指針與字符串 cout函數(shù)中參數(shù):m=m,n=nendl;程序運行結(jié)果為函數(shù)調(diào)用前:a=5,b=10函數(shù)中參數(shù):m=10,b=5函數(shù)調(diào)用后:a=5,b=10第6章 指針與字符串 說明:由程序的運行結(jié)果可以看到,函數(shù)調(diào)

35、用后變量a與b的值并未實現(xiàn)交換。其原因是,在調(diào)用函數(shù)時采用數(shù)值傳遞的方式,只是將實參a和b的值傳送給了形參m和n,如圖6-5所示;而由于實參a和b與形參m和n占用不同的內(nèi)存單元,即使被調(diào)函數(shù)中的m和n進行了交換,也無法將交換后的結(jié)果傳回給實參a和b,函數(shù)調(diào)用結(jié)束后,形參m和n被撤消,實參a和b的值仍然保持原值不變。 第6章 指針與字符串 第6章 指針與字符串 (2)地址傳遞。所謂地址傳遞,即指針變量作為函數(shù)參數(shù)。主調(diào)函數(shù)中實參的內(nèi)容是某一變量的內(nèi)存地址,被調(diào)函數(shù)的形參必須是與實參相同類型的指針變量,用以接受由實參傳過來的地址。這樣實參與形參指向相同的內(nèi)存單元,一旦被調(diào)函數(shù)中形參所指內(nèi)容發(fā)生變化

36、,意味著實參所指內(nèi)容也發(fā)生相應(yīng)的變化,函數(shù)返回后主調(diào)函數(shù)就可獲得變化后的結(jié)果。第6章 指針與字符串 【例6-7】用傳遞地址的方法改寫上例6-6,我們就能實現(xiàn)變量a和b的內(nèi)容交換,并對照圖6-6分析改進后程序的運行結(jié)果。#includevoidchangFunction(int*,int*);/函數(shù)聲明語句,參數(shù)為指針類型voidmain()inta=5,b=10;cout函數(shù)調(diào)用前:a=a,b=bendl;第6章 指針與字符串 changFunction(&a,&b);/以a、b的地址為實參調(diào)用函數(shù)cout函數(shù)調(diào)用后:a=a,b=bendl;voidchangFunction(

37、int*m,int*n)inttemp;/互換用的變量temp=*m;*m=*n;*n=temp;cout函數(shù)中參數(shù):*m=*m,*n=*nendl;第6章 指針與字符串 程序運行結(jié)果為函數(shù)調(diào)用前:a=5,b=10函數(shù)中參數(shù):*m=10,*n=5函數(shù)調(diào)用后:a=10,b=5第6章 指針與字符串 第6章 指針與字符串 由上例我們不難總結(jié)出指針變量作為函數(shù)參數(shù)的特點是,形參所指內(nèi)容改變,實參所指內(nèi)容也相應(yīng)改變。為此編程時要注意兩點:第一,實參必須是欲改變內(nèi)容的變量的地址,形參必須是與實參類型相同的指針變量,用以接受實參傳來的地址;第二,在被調(diào)函數(shù)中直接通過形參指針變量修改它所指內(nèi)存單元的內(nèi)容。第6

38、章 指針與字符串 【例6-8】編寫一個復(fù)數(shù)加法函數(shù)。 分析:復(fù)數(shù)的加法要求對參與運算的兩個復(fù)數(shù)的實部和虛部分別進行加法運算,運算的結(jié)果也有實部和虛部兩個部分。如果只利用函數(shù)的返回值,不能有效地表示一個復(fù)數(shù)的實部和虛部兩個部分。所以采用指針操作,通過指針將結(jié)果值賦予外部調(diào)用函數(shù)的變量。 函數(shù)程序代碼如下:第6章 指針與字符串 voidComplexPlus(floatfRealpartl,floatfVirtualpartl,floatfRealpart2,floatfVirtualpart2,float*pfRealR,float*pfVirtualR)*pfRealR=fRealpartl+

39、fRealpart2;*pfVirtualR=fVirtualpartl+fVirtualpart2;第6章 指針與字符串 6.4.2 指向函數(shù)的指針 1指向函數(shù)指針變量的定義與使用 在C+語言中,函數(shù)的調(diào)用實際上是通過指針來完成的。同數(shù)據(jù)一樣,程序也是保存在內(nèi)存中的。CPU在執(zhí)行程序時,首先需要找到程序的入口(開始)地址,然后從內(nèi)存中取出指令并逐條執(zhí)行。顯然,同程序一樣,函數(shù)的指針是一個函數(shù)在內(nèi)存中的入口地址。在調(diào)用一個函數(shù)時,系統(tǒng)從當(dāng)前的位置跳到該函數(shù)的入口地址處執(zhí)行指令;函數(shù)返回時,系統(tǒng)回到剛才調(diào)用函數(shù)的那條指令的位置繼續(xù)執(zhí)行程序。第6章 指針與字符串 由此可見,要調(diào)用一個函數(shù),只需要知

40、道被調(diào)用函數(shù)的入口地址,即函數(shù)的指針即可。函數(shù)名實際上就是一個指針,它指向函數(shù)的入口。我們可以定義一個指針變量,并賦予它函數(shù)名,這樣該指針變量的內(nèi)容就是該函數(shù)在內(nèi)存的入口地址。這樣的指針變量稱為指向函數(shù)的指針變量,簡稱函數(shù)指針變量。由此,我們就可以通過函數(shù)指針變量來調(diào)用它所指向的函數(shù)。 第6章 指針與字符串 函數(shù)的指針還可以聲明成變量。聲明一個函數(shù)指針變量的形式如下: (*函數(shù)指針變量名)(參數(shù)表) 注意,定義中的兩對圓括號都不要遺漏,數(shù)據(jù)類型是函數(shù)指針變量所指函數(shù)的返回值的數(shù)據(jù)類型。第6章 指針與字符串 例如,若定義函數(shù) voidFunctionA(intm,intn); 則對應(yīng)于函數(shù)Fun

41、ctionA的指針型變量可以按如下方法聲明: void(*pFPointer)(int,int); 要用已經(jīng)定義的函數(shù)指針變量來調(diào)用函數(shù),需要分兩步進行。 第一步:將函數(shù)名賦給已定義的函數(shù)指針變量。采用的格式為函數(shù)指針變量名=函數(shù)名第6章 指針與字符串 例如,可以將FunctionA的入口地址值賦予pFPointer這個函數(shù)指針變量: pFpointer=FunctionA; 第二步:使用函數(shù)指針變量調(diào)用它所指的函數(shù)。采用的格式為 (*函數(shù)指針變量名)(實參表)或函數(shù)指針變量名(實參表) 事實上,由于pFPointer和FunctionA指向同一函數(shù)入口,除了可以使用函數(shù)名FunctionA調(diào)

42、用函數(shù)外,當(dāng)然可以使用函數(shù)指針pFPointer調(diào)用函數(shù)。例如: FunctionA(3,4) 等價于 (*pFPointer)(3,4);或pFPointer(3,4); 第6章 指針與字符串 2函數(shù)指針變量作為函數(shù)的參數(shù) 函數(shù)指針變量的一個主要用途是在函數(shù)調(diào)用時把函數(shù)指針變量作為參數(shù),也就是說傳遞的不是數(shù)值,而是函數(shù)的入口地址,目的是實現(xiàn)對若干個不同函數(shù)的靈活調(diào)用。具體編程時要注意的是:主調(diào)函數(shù)的實參應(yīng)設(shè)置成將被調(diào)用的函數(shù)名,被調(diào)函數(shù)的相應(yīng)形參應(yīng)設(shè)置成接受同類型函數(shù)入口地址的函數(shù)指針變量。第6章 指針與字符串 【例6-9】將函數(shù)指針變量作為函數(shù)參數(shù)例題。#includeintadd(int

43、x,inty)returnx+y;intsub(intx,inty)returnx-y;intfunct(int(*fun)(int,int),intx,inty)第6章 指針與字符串 intresult;result=(*fun)(x,y);/等價于result=fun(x,y);returnresult;voidmain()inta=5,b=10;cinab;couta+b=funct(add,a,b)endl;couta-b=funct(sub,a,b)endl;第6章 指針與字符串 程序運行結(jié)果為輸入:323+2=53-2=1第6章 指針與字符串 6.4.3指針作為函數(shù)的返回類型 如前

44、所述,函數(shù)的數(shù)據(jù)類型是指函數(shù)返回值的類型,它可以是整型、字符型、浮點型或void(無返回值),也可以是指針類型,即函數(shù)的返回值是地址。返回值是地址的函數(shù)稱為指針函數(shù),其定義的一般形式如下: *函數(shù)名(形參表) 函數(shù)體 第6章 指針與字符串 例如: int*ip; int*fFun1(intx) . returnip; 其中fFun1是函數(shù)名,前面的“*”表示fFun1是一個指針函數(shù)(注意與函數(shù)指針的區(qū)別),它的返回值是一個int類型的地址。與此相匹配的是,在函數(shù)體內(nèi)return語句中的ip也必須是指向int型的指針變量。 第6章 指針與字符串 【例6-10】函數(shù)的返回值是指針類型例題。 cha

45、r*PointerCheck(char*pBuffer) if(*pBuffer=A)returnNULL;elsereturnpBuffer;/pBuffer不是函數(shù)內(nèi)部的局部變量 第6章 指針與字符串 6.5 指針與類、對象指針與類、對象 1. 類的指針變量 類的指針變量是一個用于保存該類對象在內(nèi)存中存儲空間首地址的指針型變量,同普通數(shù)據(jù)類型的指針變量有相同的性質(zhì)。 聲明一個類的指針變量的語法如下: *指針變量名;第6章 指針與字符串 2對象的指針 對象的指針指的是一個對象在內(nèi)存中的首地址。取得一個對象在內(nèi)存中首地址的方法同取得變量在內(nèi)存中首地址的方法一樣,都是通過取地址運算符“&

46、”。例如,若有 CStudent*pStu,Stu1; 則 pStu=&Stu1; 表示表達式&Stu1是取得對象Stu1內(nèi)存中的首地址,其值的類型是CStudent*,同類指針pStu就指向?qū)ο骃tu1在內(nèi)存中的首地址。第6章 指針與字符串 同樣,已知一個對象的指針,要訪問該對象,仍然可以使用指向運算符“*”。例如:*(pStu)就同Stu1等價。 如果已知一個對象的指針,要訪問該對象中的成員,其方法同結(jié)構(gòu)體變量的指針是相似的,既可以使用“*”運算符先取得該對象的實際“值”,然后再使用成員運算符“.”訪問數(shù)據(jù)成員和成員函數(shù),也可以使用“-”運算符直接訪問該指針所指向的對象的數(shù)

47、據(jù)成員和成員函數(shù)。 第6章 指針與字符串 例如,若有CStudentStu1;Cstudent*pStu=&Stu1;則*pStu.SetID;/其中SetID是類CStudent的數(shù)據(jù)成員pStu-SetDispl(張建華);/其中SetDispl是類CStudent的成員函數(shù)都是合法的表達式。 第6章 指針與字符串 3this指針 this指針是每個對象中隱藏的指針。this指針是默認的。當(dāng)一個對象生成后,這個對象的this指針就指向內(nèi)存中保存該對象數(shù)據(jù)的存儲空間的首地址。 在類的成員函數(shù)中使用這個this指針,就好像this指針是類的一個自動隱藏的私有成員一樣。this指針可以形

48、象地用如下定義來說明:第6章 指針與字符串 classMyClassprivate:MyClass*this;.public:MyClass();.;第6章 指針與字符串 實際上不必像上面那樣定義this指針。this指針對一個對象來說是系統(tǒng)自動生成的,主要用于在成員函數(shù)中需要把對象本身作為參數(shù)傳遞給另一個函數(shù)。我們通過以下例子來說明this指針的作用。第6章 指針與字符串 【例6-11】this指針的作用例題。#includeclassThisSampleintn;public:ThisSample();ThisSample(intm)n=m;第6章 指針與字符串 voidaddvalue(

49、intm) /定義一個非靜態(tài)成員函數(shù)ThisSampleq;q.n=n+m;/此處n相當(dāng)于this-n*this=q;/將臨時對象q的值傳回調(diào)用對象;voiddisp()coutn=nendl;第6章 指針與字符串 voidmain()ThisSamples(10);s.disp();s.addvalue(5);/相當(dāng)于函數(shù)調(diào)用:addvalue(&s,5);s.disp();程序運行結(jié)果為n=10n=15第6章 指針與字符串 6.6 指針與字符串指針與字符串 6.6.1 字符串指針 第3章我們已經(jīng)介紹過,在C+語言中,字符串是以“0”為結(jié)束標志的字符序列,是以字符數(shù)組的形式進行存儲與

50、處理的,而數(shù)組與指針又緊密相連(數(shù)組名就保存著字符串在內(nèi)存的起始地址),因此,字符串實質(zhì)上與char*型指針相對應(yīng)。第6章 指針與字符串 等價于下面兩行:char*cString;cString=IloveChina!;由此總結(jié)出有關(guān)char*型指針的兩個結(jié)論如下:char*型指針變量可以在定義時進行初始化,其形式為char*指針變量名=字符串;例如:char*myString=Thisisastring.;這樣就可以用myString這個指針來訪問字符串“Thisisastring.”了。第6章 指針與字符串 char*型的指針變量(或函數(shù)參數(shù))既可以用于接收字符串常量,也可以接收字符型數(shù)組

51、。例如: charpString=IloveChina!; char*myString=Thisisastring.; myString=pString; 最后,我們以第3章字符串的復(fù)制為例,進一步對字符串與指針的應(yīng)用進行說明。 第6章 指針與字符串 【例6-12】字符串的復(fù)制。 分析:字符串的復(fù)制就是將一個字符型數(shù)組(源字符串)的內(nèi)容照原樣復(fù)制到另一個字符型數(shù)組中。方法是,把源字符型數(shù)組中的字符依次賦予給目的字符型數(shù)組,直到碰到“0”(或0)為止。 假設(shè)源字符串保存在數(shù)組pSource中,目的字符型數(shù)組為pDestination,則用char*型指針進行字符串復(fù)制的程序如下:第6章 指針與字

52、符串 #includevoidcopy_string(char*from,char*to)/復(fù)制函數(shù)for(;*from!=0;from+,to+)*to=*from;*to=0;/賦值字符串結(jié)束標識 voidmain()第6章 指針與字符串 charpSource=Iamateacher.;charpDestination=youareastudent.;/pDestination字符串長度pSource字符串長度copy_string(pSource,pDestination);coutpSourceendl;coutpDestinationendl; 第6章 指針與字符串 程序運行結(jié)果為

53、 Iamateacher. Iamateacher. 另外,下面給出復(fù)制函數(shù)copy_string函數(shù)體的幾種等價簡化形式,請讀者自行分析理解。 (1)while(*to=*from)!=0) to+; from+; (2)while(*to+=*from+)!=0); 第6章 指針與字符串 (3)while(*from!=0)*to+=*from+;*to=0;(4)while(*from)/注意:0的ASCII碼值=0(假)*to+=*from+;*to=0;第6章 指針與字符串 6.6.2 字符串標準庫函數(shù) 實際上,C+提供了許多操作字符串?dāng)?shù)據(jù)的標準庫函數(shù),如比較字符串、搜索字符串中的字

54、符、確定字符串長度等,我們在程序設(shè)計時可直接引用。在此簡要介紹字符串處理庫(標準庫)中常用的字符串操作函數(shù)(如表6-1所示)。第6章 指針與字符串 表6-1 C+字符串處理庫(標準庫)中常用的字符串操作函數(shù) 第6章 指針與字符串 注意: 使用字符串處理庫中的函數(shù)應(yīng)在程序的開頭添加包含“string.h”頭文件的預(yù)處理命令#include。 函數(shù)strcpy將第2個參數(shù)(字符串)復(fù)制到第1個參數(shù)(字符數(shù)組)中,這個字符數(shù)組的長度應(yīng)當(dāng)足以放下字符串及其NULL終止符。函數(shù)strncpy與strcpy相似,只是strncpy指定了從字符串復(fù)制到字符數(shù)組的字符數(shù)。 第6章 指針與字符串 【例6-13】

55、例6-12字符串的復(fù)制可以直接用C+的標準庫函數(shù)strcpy()來實現(xiàn)。 #include #include voidmain() charpSource=Iamateacher.;第6章 指針與字符串 charpDestination=youareastudent.;/pDestination字符串長度pSource字符串長度strcpy(pDestination,pSource);/等價于strncpy(pDestination,pSource,16);coutpSourceendl;coutpDestinationendl; 第6章 指針與字符串 6.7 動態(tài)內(nèi)存分配與動態(tài)內(nèi)存分配與ne

56、w和和delete運算符運算符 動態(tài)內(nèi)存分配是相對于靜態(tài)內(nèi)存分配而言的。靜態(tài)內(nèi)存分配是指在編譯階段就分配好存儲單元空間,這些空間的大小在程序運行過程中是不可更改的,如變量、數(shù)組等;動態(tài)內(nèi)存分配則是指程序員在程序語句中通過調(diào)用內(nèi)存分配函數(shù)或使用內(nèi)存分配運算符取得存儲空間,通過動態(tài)內(nèi)存分配得到的空間的大小,編譯器是不知道的,完全由動態(tài)運行中的程序的當(dāng)時情況決定。 第6章 指針與字符串 靜態(tài)內(nèi)存分配和動態(tài)內(nèi)存分配在使用中的區(qū)別在于:通過靜態(tài)內(nèi)存分配取得的空間(即變量、數(shù)組等所占用的空間)程序員無須管理,編譯器在對程序進行編譯時已經(jīng)自動將管理這些空間的代碼加入到目標程序中,在作用域結(jié)束后,自動將空間歸

57、還給系統(tǒng);而通過動態(tài)內(nèi)存分配所取得的空間在使用完畢后,必須由程序員通過程序語句顯式地將其歸還給系統(tǒng)。第6章 指針與字符串 6.7.1 new運算符 new運算符用于動態(tài)分配一塊內(nèi)存空間。new運算符的使用形式如下: 指針變量=new長度 其中數(shù)據(jù)類型可以是C+語言的標準數(shù)據(jù)類型,也可以是結(jié)構(gòu)體類型、共用體類型、類類型等;長度表示該內(nèi)存空間可以容納該數(shù)據(jù)類型的數(shù)據(jù)個數(shù)。new運算符返回一個指針,這個指針指向所分配的存儲空間的第1個單元。 第6章 指針與字符串 返回的指針類型同所分配內(nèi)存空間的數(shù)據(jù)類型有關(guān)。如果數(shù)據(jù)類型是char,則返回的指針類型是char*;如果數(shù)據(jù)類型是int,則返回的指針就是

58、int*。 例如: char*CBuffer=newchar256;/分配一個可以容納256個char型數(shù)據(jù)的空間說明: 如果分配的空間長度為1個單位,則可以省略new運算符格式中的中括號和中括號中的整數(shù)。例如,float*pNum=newfloat;與float*pNum=newfloat1;等價。第6章 指針與字符串 使用new運算符分配內(nèi)存空間時,其空間長度可以是變量,也可以是數(shù)值表達式。例如: intnSize=5; int*nPInt=newintnSize+5;/分配一個可以容納10個int型數(shù)據(jù)的空間 由new分配的內(nèi)存空間是連續(xù)的,可以通過指針的變化訪問所分配空間的每一個元素。

59、 第6章 指針與字符串 例如: int*nPInt=newint10; nPInt5=100; 或 *(nPInt+5)=100; 如果當(dāng)前存儲器無足夠的內(nèi)存空間可分配,則new運算符返回0(NULL)。 第6章 指針與字符串 【例6-14】改寫字符串復(fù)制函數(shù),要求能通過源字符串的大小動態(tài)分配目的字符串的存儲空間,并返回所分配空間的首地址。 #include char*toDest; char*copy_string(char*from)/復(fù)制函數(shù) intnSize=1; while(fromnSize!=0) /求源字符串的長度并加1第6章 指針與字符串 /(注意nSize的初值賦1的作用)

60、nSize+;char*to=newcharnSize; /定義目的字符串并申請分配內(nèi)存空間toDest=to;/用非函數(shù)局部變量保存空間首地址if(to!=NULL)/申請內(nèi)存空間成功for(;*from!=0;from+,to+)*to=*from;*to=0;/賦值字符串結(jié)束標識第6章 指針與字符串 returntoDest;voidmain()charpSource=Iamateacher.;char*pDest;pDest=copy_string(pSource);if(pDest!=NULL)cout源字符串:pSourceendl;第6章 指針與字符串 cout目的字符串:pDestendl;elsecout無內(nèi)存空間進行復(fù)制操作!endl;程序運行結(jié)果為源字符串:Iamateacher.目的字符串:Iamateacher.第6章 指針與字符串 6.7.2 delete運算符 由new運算符分配的內(nèi)存空間在使用完畢后,應(yīng)該使用delete運算

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論