1、記憶體分配方式
記憶體分配方式有三種:
(1)從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在
。例如全域性變數,static變數。
(2)在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些存
儲單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3) 從堆上分配,亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意多少的記憶體,程式設計師自
己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多。
2.記憶體使用錯誤
發生記憶體錯誤是件非常麻煩的事情。編譯器不能自動發現這些錯誤,通常是在程式執行時才能捕捉到。
而這些錯誤大多沒有明顯的症狀,時隱時現,增加了改錯的難度。有時使用者怒氣沖沖地把你找來,程式卻沒
發生任何問題,你一走,錯誤又發作了。 常見的記憶體錯誤及其對策如下:
* 記憶體分配未成功,卻使用了它。
程式設計新手常犯這種錯誤,因為他們沒有意識到記憶體分配會不成功。常用解決辦法是,在使用記憶體之前檢查
指標是否為null。如果是用malloc或new來申請記憶體,應該用if(p==null) 或if(p!=null)進行防錯處理。
* 記憶體分配雖然成功,但是尚未初始化就引用它。
犯這種錯誤主要有兩個起因:一是沒有初始化的觀念;二是誤以為記憶體的預設初值全為零,導致引用初值
錯誤(例如陣列)。 記憶體的預設初值究竟是什麼並沒有統一的標準,儘管有些時候為零值,我們寧可信其無不
可信其有。所以無論用何種方式建立陣列,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。
* 記憶體分配成功並且已經初始化,但操作越過了記憶體的邊界。
例如在使用陣列時經常發生下標「多1」或者「少1」的操作。特別是在for迴圈語句中,迴圈次數很容易搞
錯,導致陣列操作越界。
* 忘記了釋放記憶體,造成記憶體洩露。
含有這種錯誤的函式每被呼叫一次就丟失一塊記憶體。剛開始時系統的記憶體充足,你看不到錯誤。終有一次
動態記憶體的申請與釋放必須配對,程式中malloc與free的使用次數一定要相同,否則肯定有錯誤
(new/delete同理)。
* 釋放了記憶體卻繼續使用它。
有三種情況:
(1)程式中的物件呼叫關係過於複雜,實在難以搞清楚某個物件究竟是否已經釋放了記憶體,此時應該重新
設計資料結構,從根本上解決物件管理的混亂局面。
(2)函式的return語句寫錯了,注意不要返回指向「棧記憶體」的「指標」或者「引用」,因為該內存在函
數體結束時被自動銷毀。
(3)使用free或delete釋放了記憶體後,沒有將指標設定為null。導致產生「野指標」。
【規則1】用malloc或new申請記憶體之後,應該立即檢查指標值是否為null。防止使用指標值為null的記憶體
【規則2】不要忘記為陣列和動態記憶體賦初值。防止將未被初始化的記憶體作為右值使用。
【規則3】避免陣列或指標的下標越界,特別要當心發生「多1」或者「少1」操作。
【規則4】動態記憶體的申請與釋放必須配對,防止記憶體洩漏。
【規則5】用free或delete釋放了記憶體之後,立即將指標設定為null,防止產生「野指標」。
二. 詳解new,malloc,globalalloc
1. new
new和delete運算子用於動態分配和撤銷記憶體的運算子
new用法:
1> 開闢單變數位址空間
1)new int; //開闢乙個存放陣列的儲存空間,返回乙個指向該儲存空間的位址.int *a = new
int 即為將乙個int型別的位址賦值給整型指標a.
2)int *a = new int(5) 作用同上,但是同時將整數賦值為5
2> 開闢陣列空間
一維: int *a = new int[100];開闢乙個大小為100的整型陣列空間
一般用法: new 型別 [初值]
delete用法:
1> int *a = new int;
delete a; //釋放單個int的空間
2>int *a = new int[5];
delete a; //釋放int陣列空間
要訪問new所開闢的結構體空間,無法直接通過變數名進行,只能通過賦值的指標進行訪問.
用new和delete可以動態開闢,撤銷位址空間.在程式設計序時,若用完乙個變數(一般是暫時儲存的陣列),
下次需要再用,但卻又想省去重新初始化的功夫,可以在每次開始使用時開闢乙個空間,在用完後撤銷它.
2. malloc
原型:extern void *malloc(unsigned int num_bytes);
用法:#i nclude 或#i nclude
功能:分配長度為num_bytes位元組的記憶體塊
說明:如果分配成功則返回指向被分配記憶體的指標,否則返回空指標null。
當記憶體不再使用時,應使用free()函式將記憶體塊釋放。
malloc的語法是:指標名=(資料型別*)malloc(長度),(資料型別*)表示指標.
說明:malloc 向系統申請分配指定size個位元組的記憶體空間。返回型別是 void* 型別。void* 表示未確定型別
的指標。c,c++規定,void* 型別可以強制轉換為任何其它型別的指標。
malloc()函式的工作機制
malloc函式的實質體現在,它有乙個將可用的記憶體塊連線為乙個長長的列表的所謂空閒鍊錶。呼叫malloc
函式時,它沿連線表尋找乙個大到足以滿足使用者請求所需要的記憶體塊。然後,將該記憶體塊一分為二(一塊的大
小與使用者請求的大小相等,另一塊的大小就是剩下的位元組)。接下來,將分配給使用者的那塊記憶體傳給使用者,並
將剩下的那塊(如果有的話)返回到連線表上。呼叫free函式時,它將使用者釋放的記憶體塊連線到空閒鏈上。到
最後,空閒鏈會被切成很多的小記憶體片段,如果這時使用者申請乙個大的記憶體片段,那麼空閒鏈上可能沒有可以
滿足使用者要求的片段了。於是,malloc函式請求延時,並開始在空閒鏈上翻箱倒櫃地檢查各記憶體片段,對它們
進行整理,將相鄰的小空閒塊合併成較大的記憶體塊。
和new的不同
從函式宣告上可以看出。malloc 和 new 至少有兩個不同: new 返回指定型別的指標,並且可以自動計算所需
要大小。比如:
int *p;
p = new int; //返回型別為int* 型別(整數型指標),分配大小為 sizeof(int);
或:int* parr;
parr = new int [100]; //返回型別為 int* 型別(整數型指標),分配大小為 sizeof(int) * 100;
而 malloc 則必須由我們計算要位元組數,並且在返回後強行轉換為實際型別的指標。
int* p;
p = (int *) malloc (sizeof(int));
第一、malloc 函式返回的是 void * 型別,如果你寫成:p = malloc (sizeof(int)); 則程式無法通過編譯,
報錯:「不能將 void* 賦值給 int * 型別變數」。所以必須通過 (int *) 來將強制轉換。
第二、函式的實參為 sizeof(int) ,用於指明乙個整型資料需要的大小。如果你寫成:
int* p = (int *) malloc (1);
**也能通過編譯,但事實上只分配了1個位元組大小的記憶體空間,當你往裡頭存入乙個整數,就會有3個位元組無
家可歸,而直接「住進鄰居家」!造成的結果是後面的記憶體中原有資料內容全部被清空。
三 new malloc 區別
1、malloc與free是c++/c語言的標準庫函式,new/delete是c++的運算子。它們都可用於申請動態記憶體和釋放記憶體。
2、new 不止是分配記憶體,而且會呼叫類的建構函式,同理delete會呼叫類的析構函式,而malloc則只分配記憶體,不會進行初始化類成員的工作,同樣free也不會呼叫析構函式
3、記憶體洩漏對於malloc或者new都可以檢查出來的,區別在於new可以指明是那個檔案的那一行,而malloc沒有這些資訊。
4、new 和 malloc效率比較
new可以認為是malloc加建構函式的執行。
new出來的指標是直接帶型別資訊的。
而malloc返回的都是void指標
C 記憶體 new與malloc分配記憶體區別
一關於記憶體 1 記憶體分配方式 記憶體分配方式有三種 1 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在 例如全域性變數,static變數。2 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些存 儲單元自動被釋放。棧...
C 記憶體分配new和malloc的區別
這裡有一篇講的很詳細new和malloc的區別 總結一下 1.new delete是操作符,malloc free是函式 2.malloc分配記憶體需指定大小,且只能是一般資料型別,分配成功返回void 需要強制型別轉換,分配失敗返回null,需手動檢查是否分配成功 new分配記憶體無需指定大小,可...
new 與malloc申請記憶體區別
首先我們需要了解堆與棧的概念。區分堆記憶體與棧記憶體的區別。以及堆與棧訪問速度的差異的原因。1.屬性 new delete是c 關鍵字,需要編譯器支援。malloc free是庫函式,需要標頭檔案支援。2.引數 使用new 操作副申請記憶體分配時無須制定記憶體塊的大小,編譯器會根據型別資訊自行計算。...