隨著我們C/C++學習的深入,我們很有必要對計算機的內存管理進行一定的了解,這樣才能對這些高級程序設計語言運用自如。在這裡我們一起來討論下內存管理相關的知識。
一個由C/C++編譯的程序占用的內存分為以下幾個部分
1、棧區stack)— 由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。
2、堆區heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由操作系統OS)回收。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表,呵呵。
3、全局區靜態區)static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。- 程序結束後由系統自動釋放
4、文字常量數據)區—常量字符串就是放在這裡的。 程序結束後由系統自動釋放
5、程序代碼區—存放函數體的二進制代碼。
常見的內存管理中的錯誤及其對策如下:
1)內存分配未成功,卻使用了它。
編程新手常犯這種錯誤,因為他們沒有意識到內存分配會不成功。常用解決辦法是,在使用內存之前檢查指針是否為NULL。如果指針p是函數的參數,那麼在函數的入口處用assert(p!=NULL)進行檢查。如果是用malloc或new來申請內存,應該用if(p==NULL)或if(p!=NULL)進行防錯處理。
2)內存分配雖然成功,但是尚未初始化就引用它。
犯這種錯誤主要有兩個起因:
一是沒有初始化的觀念;
二是誤以為內存的缺省初值全為零,導致引用初值錯誤例如數組)。
內存的缺省初值究竟是什麼並沒有統一的標准,盡管有些時候為零值,我們寧可信其無不可信其有。所以無論用何種方式創建數組,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩,要不然將容易使你的代碼暗藏臭蟲哦^-^。
3)內存分配成功並且已經初始化,但操作越過了內存的邊界。
例如在使用數組時經常發生下標“多1”或者“少1”的操作。特別是在for循環語句中,循環次數很容易搞錯,導致數組操作越界。
4)忘記了釋放內存,造成內存洩露。
含有這種錯誤的函數每被調用一次就丟失一塊內存,這也太大方了些吧!要清楚計算機的內存空間是非常的寶貴的哦!剛開始時系統的內存充足,你看不到錯誤。終有一次程序突然死掉,系統出現提示:內存耗盡。
動態內存的申請與釋放必須配對,程序中malloc與free的使用次數一定要相同,否則肯定有錯誤new/delete同理)。
5)釋放了內存卻繼續使用它。
有三種情況:
1)程序中的對象調用關系過於復雜,實在難以搞清楚某個對象究竟是否已經釋放了內存,此時應該重新設計數據結構,從根本上解決對象管理的混亂局面。
2)函數的return語句寫錯了,注意不要返回指向“棧內存”的“指針”或者“引用”,因為該內存在函數體結束時被自動銷毀。
3)使用free或delete釋放了內存後,沒有將指針設置為NULL。導致產生“野指針”。
6)指針被強制轉換成不匹配的數據結構
內存使用規則
規則1】用malloc或new申請內存之後,應該立即檢查指針值是否為NULL。防止使用指針值為NULL的內存。
規則2】不要忘記為數組和動態內存賦初值。防止將未被初始化的內存作為右值使用。
規則3】避免數組或指針的下標越界,特別要當心發生“多1”或者“少1”操作。
規則4】動態內存的申請與釋放必須配對,防止內存洩漏。
規則5】用free或delete釋放了內存之後,立即將指針設置為NULL,防止產生“野指針”。
C++/C程序中,指針和數組在不少地方可以相互替換著用,讓人產生一種錯覺,以為兩者是等價的,但事實卻是兩者存在著本質的區別。
數組要麼在靜態存儲區被創建如全局數組),要麼在棧上被創建。數組名對應著而不是指向)一塊內存,其地址與容量在生命期內保持不變,只有數組的內容可以改變。
指針可以隨時指向任意類型的內存塊,它的特征是“可變”,所以我們常用指針來操作動態內存。
指針遠比數組靈活,但也更危險,稍不注意,指錯了對象會惹禍上身哦!所以在使用指針的時候要特別的謹慎。先談到這裡為止,以後再遇到與計算內存相關的問題在繼續進行總結歸納。
注:這裡有相當多的部分是我在網上查找到並借鑒其他高人的資料進行了一定的總結和修改後寫出來的!^-^
本文出自 “成長之路” 博客,請務必保留此出處http://7905648.blog.51cto.com/7895648/1295016