關(guān)于函數(shù)的高級(jí)專題_第1頁
關(guān)于函數(shù)的高級(jí)專題_第2頁
關(guān)于函數(shù)的高級(jí)專題_第3頁
關(guān)于函數(shù)的高級(jí)專題_第4頁
關(guān)于函數(shù)的高級(jí)專題_第5頁
已閱讀5頁,還剩23頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、第7章 關(guān)于函數(shù)的高級(jí)專題合理使用函數(shù)能將程序模塊化,大大降低了問題的規(guī)模,提高了編碼效率,方便以后復(fù)用代碼。函數(shù)的參數(shù)傳遞有傳值,傳指針和傳引用3種方式,從類型的角度上看,參數(shù)不僅僅可以是系統(tǒng)內(nèi)建的數(shù)據(jù)類型,還可以是數(shù)組、結(jié)構(gòu)以及后面要介紹的類對(duì)象等等,同時(shí),內(nèi)存使用注意事項(xiàng)、函數(shù)與指針的關(guān)系也是學(xué)習(xí)C+必須邁過的檻。7.1 內(nèi)存使用錯(cuò)誤剖析編寫代碼時(shí),少不了和內(nèi)存打交道,很多程序員對(duì)此提心吊膽,稱內(nèi)存為“雷區(qū)”或“bug集中營”似乎并不過份。即使是久經(jīng)沙場(chǎng)的老手,有時(shí)也難免落入內(nèi)存錯(cuò)誤的陷阱。本節(jié)幫助讀者了解這些常見的錯(cuò)誤,在編程時(shí)加以注意,把出錯(cuò)的概率降到最低。7.1.1 內(nèi)存泄露使用n

2、ew或malloc()動(dòng)態(tài)申請(qǐng)的內(nèi)存,如果不再使用,應(yīng)該把它釋放掉,為程序節(jié)省內(nèi)存空間,方便后面的使用。在C/C+中,內(nèi)存管理器不會(huì)自動(dòng)回收不再使用的內(nèi)存。如果忘記釋放不再使用的內(nèi)存,在程序的運(yùn)行過程中,這些內(nèi)存就不能再被使用用,就造成了所謂的“內(nèi)存泄露”。內(nèi)存泄露是最為常見的錯(cuò)誤,現(xiàn)在的計(jì)算機(jī)配置比較高,內(nèi)存容量很大,一兩處內(nèi)存泄露通常不至于讓程序崩潰,也不會(huì)出現(xiàn)邏輯上的錯(cuò)誤,進(jìn)程退出時(shí),系統(tǒng)會(huì)自動(dòng)釋放該進(jìn)程所有相關(guān)的內(nèi)存,所以內(nèi)存泄露的后果相對(duì)來說并不是災(zāi)害性的。但這并不意味著完全沒有危險(xiǎn),如果程序規(guī)模較大、長時(shí)間運(yùn)行,或者是內(nèi)存資源相對(duì)緊張的場(chǎng)合,內(nèi)存泄露過多會(huì)導(dǎo)致內(nèi)存耗盡,系統(tǒng)沒有后繼

3、內(nèi)存可以使用,程序可能會(huì)崩潰。第6章講過,代碼塊中聲明的局部變量在代碼塊執(zhí)行完畢后會(huì)自動(dòng)消亡,那如果是在代碼塊中申請(qǐng)的動(dòng)態(tài)內(nèi)存,系統(tǒng)會(huì)自動(dòng)回收么,答案是否定的,如:if ( condition )int* p = new int8;7.1.2 野指針前面提到“指針消亡,并不意味著其指向的內(nèi)存會(huì)被自動(dòng)釋放”,同樣“釋放動(dòng)態(tài)內(nèi)存,并不意味著指針會(huì)消亡,也不意味著指針的值會(huì)改變”,如:int* p=new int8;delete p;指向完delete p后,指針p是不是就自動(dòng)消亡了呢,錯(cuò),不論是使用delete/delete還是使用free(),指針p非但不會(huì)消亡,其值也保持不變,并不會(huì)變?yōu)閚ul

4、l。這時(shí),使用“if (p!=null)”進(jìn)行處理也無法起到防錯(cuò)作用。為此,指針被free或delete/delete后,一定要置為null,沒有置為null的指針常稱為“野指針”,釋放掉的堆內(nèi)存會(huì)被內(nèi)存管理器重新分配,野指針指向的內(nèi)存已經(jīng)被賦予新的意義。如果使用野指針釋放或再次訪問這塊內(nèi)存,會(huì)給程序帶來災(zāi)難性的后果。7.1.3 試圖修改常量程序中出現(xiàn)的字符串常量和其他全局常量(如全局const常量),是存放在.rodata里面的,.rodata內(nèi)存頁面是不能修改的,試圖對(duì)常量修改,會(huì)引發(fā)內(nèi)存錯(cuò)誤,如代碼72 。7.1.4 用錯(cuò)sizeof運(yùn)算符sizeof()可以計(jì)算數(shù)組的大小(字節(jié)數(shù)),但

5、對(duì)指針來說,sizeof僅僅得到指針變量的字節(jié)數(shù)。但當(dāng)數(shù)組作為函數(shù)的參數(shù)進(jìn)行傳遞時(shí),數(shù)組退化為同類型的指針,用sizeof是無法取得數(shù)組的大小的。代碼73演示了sizeof的用法:7.1.5 內(nèi)存越界訪問使用指針和數(shù)組訪問某塊內(nèi)存區(qū)域時(shí),編譯器并不會(huì)對(duì)數(shù)組下標(biāo)是否越界、指針是否有效進(jìn)行檢查,如果不注意,很容易造成內(nèi)存越界訪問的錯(cuò)誤,內(nèi)存越界訪問有兩種:一種是讀越界,一種是寫越界,常稱作緩沖區(qū)溢出。讀越界,即讀了不屬于自己的數(shù)據(jù),如果所讀的內(nèi)存地址是無效的,程序會(huì)立刻崩潰,但如果所讀內(nèi)存地址是有效的,在讀的時(shí)候不會(huì)出問題,但讀到的數(shù)據(jù)是隨機(jī)的,會(huì)產(chǎn)生不可預(yù)料的后果。寫越界,即往不該寫的內(nèi)存地址空

6、間中寫了東西,這往往會(huì)給程序帶來很多匪夷所思的錯(cuò)誤和BUG,有些癥狀是隨機(jī)的,時(shí)有時(shí)無,給問題分析帶來很多的困難。一些輔助工具可以幫忙檢查內(nèi)存越界,但從根本上說,在編程時(shí)應(yīng)十分小心,特別是對(duì)于外部傳入的參數(shù)要仔細(xì)檢查,另外,要做好程序的防錯(cuò)處理。7.1.6 變量的初始化不論是指針變量,還是普通變量,一定要時(shí)刻牢記“初始化”,雖然編譯器會(huì)對(duì)有的變量自動(dòng)初始化為0,但在聲明變量時(shí)就對(duì)它進(jìn)行初始化,是一個(gè)編程的好習(xí)慣,還要重視編譯器的警告信息,發(fā)現(xiàn)有引用未初始化的變量,立即修改過來。7.2 重申:函數(shù)參數(shù)傳遞和返回機(jī)制前面已經(jīng)提及,函數(shù)的參數(shù)傳遞有值傳遞、指針傳遞和引用傳遞,函數(shù)返回也可是返回值、返

7、回指針或返回引用。拋開引用傳遞,對(duì)值和指針,不論是參數(shù)傳遞還是函數(shù)返回,理解“副本”的概念十分重要。7.2.1 參數(shù)傳遞時(shí)的“副本”先來看一下函數(shù)調(diào)用的過程,不論是值傳遞還是指針傳遞,編譯器都要為每個(gè)函數(shù)制作臨時(shí)副本,函數(shù)體中對(duì)參數(shù)的修改都是對(duì)副本的修改,對(duì)傳值調(diào)用來說,對(duì)副本的任何操作不會(huì)對(duì)傳入的參數(shù)對(duì)象有任何的影響,這很好理解,但對(duì)傳指針調(diào)用來說,情況稍顯復(fù)雜,很多人對(duì)此存在誤解。指針參數(shù)傳遞的示例代碼見代碼74。7.2.2 函數(shù)返回時(shí)的“副本”函數(shù)執(zhí)行完畢后,函數(shù)內(nèi)部聲明的局部變量會(huì)自動(dòng)消亡,對(duì)應(yīng)的內(nèi)存被釋放,由內(nèi)存管理器收回,但返回值會(huì)被放置(復(fù)制)到指定位置(可能是CPU寄存器,也可

8、能是某個(gè)內(nèi)存單元),然后上級(jí)函從這個(gè)位置取得返回值。這個(gè)位置,可以看成是函數(shù)返回值的“副本”,這解釋了為什么可以用“return 局部變量;”來返回一個(gè)值,示例見代碼76。7.3 函數(shù)與指針在前面的章節(jié)中已經(jīng)介紹了函數(shù)的傳指針參數(shù)調(diào)用,返回指針,根據(jù)數(shù)組名和指針的等價(jià)性,函數(shù)的參數(shù)也可以是數(shù)組,在這些基本概念的基礎(chǔ)上,本節(jié)討論指向函數(shù)的指針以及帶參主函數(shù)的相關(guān)內(nèi)容。7.3.1 指向函數(shù)的指針函數(shù)是一組代碼的封裝體,這組代碼在內(nèi)存中占有一片存儲(chǔ)空間,該空間的起始地址存放在以函數(shù)名為名的單元的,換言之,函數(shù)名就是指向函數(shù)的常指針,這有點(diǎn)類似于數(shù)組名是指向數(shù)組內(nèi)存空間的常指針。(1)函數(shù)指針的聲明和

9、初始化(2)函數(shù)指針使用舉例7.3.2 typedef為了避免讀者對(duì)typedef的用法產(chǎn)生誤解,前面一直沒有介紹typedef的相關(guān)內(nèi)容,介紹完函數(shù)指針,來看看typedef的相關(guān)內(nèi)容。typedef用來給一個(gè)已經(jīng)存在的類型聲明一個(gè)別名,舉一個(gè)最簡單的例子:typedef int* int_p;/不要忘記分號(hào)typedef為int* 引入了一個(gè)新的助記符int_p,可以在程序中使用int_p聲明指向int型變量的指針,如:int_p pA,pB;上述代碼聲明了兩個(gè)int型指針變量pA和pB,應(yīng)當(dāng)注意:typedef不同于編譯預(yù)處理命令define,這種不同主要體現(xiàn)在兩個(gè)方面:(1)#defi

10、ne是預(yù)處理指令,在編譯預(yù)處理時(shí)進(jìn)行簡單的替換,不做正確性檢查,不管含義,只是簡單的替換,如:#define PI 3.14(2)define結(jié)構(gòu)可以抽象為:define A B7.3.3 通過函數(shù)指針將函數(shù)作為另一個(gè)函數(shù)的參數(shù)函數(shù)指針的一個(gè)功用是把函數(shù)地址作為參數(shù)傳送,以提高函數(shù)的通用性和靈活性,如代碼710 :7.3.4 函數(shù)指針數(shù)組指向函數(shù)的指針還可以組成指針數(shù)組,稱為函數(shù)指針數(shù)組。函數(shù)指針數(shù)組的使用范例見代碼:(詳細(xì)內(nèi)容請(qǐng)參照本書)7.3.5 返回函數(shù)指針的函數(shù)和普通指針一樣,函數(shù)指針也可以作為另一個(gè)函數(shù)的返回值,如代碼712:7.4 函數(shù)與數(shù)組前面已經(jīng)討論過數(shù)組和指針的關(guān)系,知道數(shù)組

11、名實(shí)際上是指向數(shù)組所占內(nèi)存單元的常指針,由此可知,和指針一樣,數(shù)組既可以作函數(shù)的參數(shù),也可以作函數(shù)的返回值。7.4.1 數(shù)組名作函數(shù)參數(shù)數(shù)組名用作函數(shù)參數(shù)時(shí),用以向程序傳遞數(shù)組所占內(nèi)存單元的首地址,數(shù)組名參數(shù)與指針參數(shù)的用法幾乎完全一致。有數(shù)組參數(shù)的函數(shù)原型的一般形式為:返回類型 函數(shù)名(數(shù)組名 ,其他參數(shù))習(xí)慣上在參數(shù)列表中要指明數(shù)組元素的個(gè)數(shù),在本章前面已經(jīng)說明,在函數(shù)內(nèi)部使用sizeof(數(shù)組名)返回的只是指針大小,而不是數(shù)組大小,因此,在參數(shù)列表中顯式注明數(shù)組元素的個(gè)數(shù)是個(gè)好的編程習(xí)慣,當(dāng)然,如果能保證不會(huì)出現(xiàn)越界訪問的情況,這個(gè)參數(shù)可以省略。理論上,“數(shù)組名”中是空的,沒有數(shù)字,如果

12、在其中寫明元素大小,編譯器也不予理會(huì),不會(huì)做錯(cuò)誤檢驗(yàn)。7.4.2 通過指針得到多于1個(gè)的回傳值理論上說,C+函數(shù)最多只能有1個(gè)返回值(return返回值),因此,由函數(shù)返回?cái)?shù)組似乎是不可能的,實(shí)際上,使用指針可以使函數(shù)得到多于1個(gè)回傳值。(1)返回指針變量返回指針變量,便可以對(duì)指針指向的一片內(nèi)存區(qū)域進(jìn)行讀寫,需要注意的是:不可返回指向棧內(nèi)存的指針,否則會(huì)出現(xiàn)“野指針”內(nèi)存錯(cuò)誤。(2)通過指針參數(shù)修改多個(gè)變量的值。7.5 函數(shù)與結(jié)構(gòu)體、共用體及類對(duì)象前面已經(jīng)講過結(jié)構(gòu)體和共用體的概念,結(jié)構(gòu)體和共用體將數(shù)據(jù)整合為一個(gè)單獨(dú)的實(shí)體。結(jié)構(gòu)體變量、共用體變量以及后面要介紹到的類對(duì)象,用法都接近于普通的變量,

13、對(duì)結(jié)構(gòu)體變量、共用體變量和類對(duì)象來說,函數(shù)支持其傳值、傳指針和傳引用調(diào)用,同時(shí),函數(shù)可返回結(jié)構(gòu)體變量、共用體變量和類對(duì)象,也可返回指向這些變量的指針和引用。下面以結(jié)構(gòu)體來討論使用方式,共用體和類對(duì)象與結(jié)構(gòu)體在函數(shù)調(diào)用和返回的機(jī)制上是一致的。7.5.1 3種參數(shù)調(diào)用同其他變量一樣,結(jié)構(gòu)變量也可以作為函數(shù)的參數(shù),請(qǐng)看代碼。(詳細(xì)內(nèi)容請(qǐng)參照本書)7.5.2 3種返回機(jī)制函數(shù)的返回機(jī)制同樣有返回結(jié)構(gòu)變量,返回指向結(jié)構(gòu)變量的指針和返回引用3種方式,和參數(shù)傳遞一樣,返回結(jié)構(gòu)變量需要復(fù)制“結(jié)果”,浪費(fèi)時(shí)間和空間,傳遞指針和引用能有效提高效率,詳細(xì)的用法與第6章中講述的普通變量的3種返回機(jī)制完全一致。7.6

14、函數(shù)編寫的建議本節(jié)簡單討論下如何寫出高效,不易出錯(cuò)的代碼,當(dāng)然,這些建議只是最基本的幾條,在網(wǎng)絡(luò)上或者專門討論C+編程技巧的教材中,討論函數(shù)編寫原則和建議的篇幅是這里的幾十倍,這里權(quán)當(dāng)是拋磚引玉,有效與否還靠讀者的理解和檢驗(yàn)。7.6.1 合理使用const在指針傳遞或引用傳遞時(shí),如果參數(shù)僅僅是輸入用,則應(yīng)在類型前加const,以防止指針在函數(shù)體內(nèi)被意外修改,若輸入?yún)?shù)采用“值傳遞”方式,函數(shù)將自動(dòng)產(chǎn)生臨時(shí)變量用于復(fù)制該參數(shù),該參數(shù)本就不需要保護(hù),不用const修飾。 對(duì)于非內(nèi)部數(shù)據(jù)類型的輸入?yún)?shù),尤其是占內(nèi)存字節(jié)較多的參數(shù),應(yīng)該將“值傳遞”改為“const引用傳遞”,以提高效率。但對(duì)內(nèi)部數(shù)據(jù)類

15、型的輸入?yún)?shù)而言,不要將“值傳遞”的方式改為“const引用傳遞”。否則既達(dá)不到提高效率的目的,又降低了函數(shù)的可理解性。C+中,返回值也可用const修飾,這樣,在返回引用或指針時(shí),不允許使用如下述代碼的形式對(duì)返回值改寫:函數(shù)名(參數(shù)表)表達(dá)式;7.6.2 檢查輸入?yún)?shù)的有效性很多函數(shù)代碼本身并沒有太大問題,常常是輸入?yún)?shù)出錯(cuò)或出現(xiàn)了沒有考慮到的情況,推薦的檢查方式是采用assert宏,關(guān)于assert宏的詳細(xì)介紹請(qǐng)參考第20章。此外,還要檢查一些全局變量、指針等是否有效。7.6.3 函數(shù)返回類型的判斷返回值是傳值、傳指針還是傳引用,在函數(shù)設(shè)計(jì)和編寫過程中要規(guī)劃好。這不僅牽扯到函數(shù)返回的效率,而且還要保證返回的指針和引用指向的不是棧內(nèi)存,否則,極容易形成“野指針”。7.7 小結(jié)本章討論了一些和函數(shù)相關(guān)的相對(duì)高階的內(nèi)容,以前面幾章的內(nèi)容為基礎(chǔ),首先介紹了C+程序中經(jīng)常出現(xiàn)的內(nèi)存錯(cuò)誤,這往往是很多初學(xué)者忽略的東西,結(jié)果讓程序到處是漏洞,無從運(yùn)行。對(duì)函數(shù)參數(shù)傳遞和返回機(jī)制進(jìn)行了“重申”,理解“副本”的概念,不論是傳值還是傳指針調(diào)用,都存在“復(fù)制品”,不同的是傳指針僅僅復(fù)制指針變量占據(jù)的4個(gè)字節(jié)(某些系統(tǒng)是2個(gè)字節(jié)),效率相比傳值調(diào)用要高,尤

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論