C 靜態(tài)內(nèi)存、動態(tài)內(nèi)存問題

(1)C語言跟內(nèi)存分配方式

<1>從靜態(tài)存儲區(qū)域分配.
內(nèi)存在程序編譯的時候就已經(jīng)分配好,這塊內(nèi)存在程序的整個運(yùn)行期間都存在。例如全局變量、static變量。

<2>在棧上創(chuàng)建
在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。

<3>從堆上分配,亦稱動態(tài)內(nèi)存分配.
程序在運(yùn)行的時候用malloc或new申請任意多少的內(nèi)存,程序員自己負(fù)責(zé)在何時用free或delete釋放內(nèi)存。動態(tài)內(nèi)存的生存期由用戶決定,使用非常靈活,但問題也最多。

(2)C語言跟內(nèi)存申請相關(guān)的函數(shù)主要有 alloca、calloc、malloc、free、realloc等。

<1>alloca是向棧申請內(nèi)存,因此無需釋放,用完會自動釋放。
<2>malloc分配的內(nèi)存是位于堆中的,并且沒有初始化內(nèi)存的內(nèi)容,因此基本上malloc之后,調(diào)用函數(shù)memset來初始化這部分的內(nèi)存空間。
<3>calloc和malloc一樣從堆中申請內(nèi)存,并且將初始化這部分的內(nèi)存。無需調(diào)用memset函數(shù)來初始化。
<4>realloc則對malloc申請的內(nèi)存進(jìn)行大小的調(diào)整。
<5>申請的堆內(nèi)存最終需要通過函數(shù)free來釋放。

當(dāng)程序運(yùn)行過程中malloc了,但是沒有free的話,會造成內(nèi)存泄漏。一部分的內(nèi)存沒有被使用,但是由于沒有free,因此系統(tǒng)認(rèn)為這部分內(nèi)存還在使用,造成不斷的向系統(tǒng)申請內(nèi)存,使得系統(tǒng)可用內(nèi)存不斷減少。但是內(nèi)存泄漏僅僅指程序在運(yùn)行時,程序退出時,OS將回收所有的資源。因此,適當(dāng)?shù)闹貑⒁幌鲁绦?,有時候還是有點(diǎn)作用。

【注意】

三個函數(shù)的申明分別是:

        void* malloc(unsigned size);
        void* realloc(void* ptr, unsigned newsize);  
        void* calloc(size_t numElements, size_t sizeOfElement); 

都在stdlib.h函數(shù)庫內(nèi),它們的返回值都是請求系統(tǒng)分配的地址,如果請求失敗就返回NULL。
(1)函數(shù)malloc()
在內(nèi)存的動態(tài)存儲區(qū)中分配一塊長度為size字節(jié)的連續(xù)區(qū)域,參數(shù)size為需要內(nèi)存空間的長度,返回該區(qū)域的首地址。
(2)函數(shù)calloc()
與malloc相似,參數(shù)sizeOfElement為申請地址的單位元素長度,numElements為元素個數(shù),即在內(nèi)存中申請numElements*sizeOfElement字節(jié)大小的連續(xù)地址空間。
(3)函數(shù)realloc()
給一個已經(jīng)分配了地址的指針重新分配空間,參數(shù)ptr為原有的空間地址,newsize是重新申請的地址長度。注意使用此函數(shù)時,最好將返回值先賦給一個臨時指針temp_ptr,然后判斷temp_ptr是否為空。若為空,說明申請更多內(nèi)存失敗,此時不能將NULL指針賦給原內(nèi)存ptr指針,否則會導(dǎo)致原內(nèi)存泄漏數(shù)據(jù)丟失。只有在確認(rèn)temp_ptr不為空時,才能將其賦值給原指針ptr。

區(qū)別:
(1)函數(shù)malloc不能初始化所分配的內(nèi)存空間,而函數(shù)calloc能。如果由malloc()函數(shù)分配的內(nèi)存空間原來沒有被使用過,則其中的每一位可能都是0;反之,如果這部分內(nèi)存曾經(jīng)被分配過,則其中可能遺留有各種各樣的數(shù)據(jù)。也就是說,使用malloc()函數(shù)的程序開始時(內(nèi)存空間還沒有被重新分配)能正常進(jìn)行,但經(jīng)過一段時間(內(nèi)存空間已經(jīng)被重新分配)可能會出現(xiàn)問題,導(dǎo)致獲取到奇怪的臟數(shù)據(jù)。
(2)函數(shù)calloc() 會將所分配的內(nèi)存空間中的每一位都初始化為零,也就是說,如果你是為字符類型或整數(shù)類型的元素分配內(nèi)存,那么這些元素將保證會被初始化為0;如果你是為指針類型的元素分配內(nèi)存,那么這些元素通常會被初始化為空指針;如果你為浮點(diǎn)型數(shù)據(jù)分配內(nèi)存,則這些元素會被初始化為浮點(diǎn)型的零0.0。
(3)函數(shù)malloc向系統(tǒng)申請分配指定size個字節(jié)的內(nèi)存空間。返回類型是 void類型。void表示未確定類型的指針。C,C++規(guī)定,void* 類型可以強(qiáng)制轉(zhuǎn)換為任何其它類型的指針,因此使用此類函數(shù)時都應(yīng)該在函數(shù)前加上強(qiáng)制類型轉(zhuǎn)換。
(4)realloc可以對給定的指針?biāo)傅目臻g進(jìn)行擴(kuò)大或者縮小,無論是擴(kuò)張或是縮小,原有內(nèi)存的中內(nèi)容將保持不變。當(dāng)然,對于縮小,則被縮小的那一部分的內(nèi)容會丟失。realloc并不保證調(diào)整后的內(nèi)存空間和原來的內(nèi)存空間保持同一內(nèi)存地址。相反,realloc返回的指針很可能指向一個新的地址。
(5)realloc是從堆上分配內(nèi)存的。當(dāng)擴(kuò)大一塊內(nèi)存空間時,realloc()首先試圖直接從堆上現(xiàn)存的數(shù)據(jù)后面的那些字節(jié)中獲得附加的字節(jié),如果能夠滿足,自然天下太平直接附加;如果數(shù)據(jù)后面的字節(jié)不夠,問題就出來了,那么就使用堆上第一個有足夠大小的自由塊,現(xiàn)存的數(shù)據(jù)然后就被拷貝至新的位置,而老塊則釋放回堆上。這句話傳遞的一個重要的信息就是數(shù)據(jù)可能被移動。當(dāng)然,如果堆上的自由內(nèi)存沒有任何一塊連續(xù)的內(nèi)存能滿足,那就只能返回NULL空指針了,所以要注意判斷,此時若返回空應(yīng)該提示獲取擴(kuò)展內(nèi)存失敗。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容