1. 程式人生 > >malloc與new相關

malloc與new相關

初始化 空字符 原理 支持 oca 容器 pan 新的 set

  malloc函數:malloc的全稱是memory allocation,中文叫動態內存分配。作用是向系統申請分配指定size個字節的內存空間,函數原型為:

extern void *malloc(unsigned int num_bytes);

  void*表示未確定類型的指針,C,C++規定,void* 類型可以通過類型轉換強制轉換為任何其它類型的指針。

  free函數:void free(void *FirstByte): 該函數是將之前用malloc分配的空間還給程序或者是操作系統,也就是釋放了這塊內存,讓它重新得到自由。

  其功能為在堆中申請一塊連續的可用的內存;使用中有如下需要關註的點:

  1.malloc分配的內存大小至少為size參數所指定的字節數.

  2.malloc的返回值是一個指針,指向一段可用內存的起始地址.

  3.多次調用malloc所分配的地址不能有重疊部分,除非某次malloc所分配的地址被釋放掉.

  4.malloc應該盡快完成內存分配並返回.

  5.實現malloc時應同時實現內存大小調整和內存釋放函數(即realloc和free).

用法示例:

#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
int main() {
    char *ptr;
    ptr 
= (char*)malloc(8); //返回類型為void*,強制轉換 if (NULL == ptr) //申請後務必檢查是否成功,因為對內存不足等原因有可能申請失敗 { exit (1); } if(ptr) printf("Memory Allocated at: %x/n",ptr); free(ptr); //申請同時釋放 ptr = NULL; //free釋放的只是內存,ptr指針還在,所以記得將ptr指向NULL return
0; }

malloc函數使用時需要註意的要點:

  1、如果有足夠空間用於擴大mem_address指向的內存塊,則分配額外內存,並返回mem_address. 這裏說的是“擴大”,我們知道,realloc是從堆上分配內存的,當擴大一塊內存空間時, realloc()試圖直接從堆上現存的數據後面的那些字節中獲得附加的字節,如果能夠滿足,自然天下太平。也就是說,如果原先的內存大小後面還有足夠的空閑空間用來分配,加上原來的空間大小= newsize,得到的是一塊連續的內存。

  2、如果原先的內存大小後面沒有足夠的空閑空間用來分配,那麽從堆中另外找一塊newsize大小的內存。 並把原來大小內存空間中的內容復制到newsize中。返回新的mem_address指針。

  3、malloc函數返回值情況

  返回的是一個void類型的指針,調用成功。(這就再你需要的時候進行強制類型轉換)

  返回NULL,當需要擴展的大小(第二個參數)為0並且第一個參數不為NULL,此時原內存變成了“freed(遊離)”的了。

  返回NULL,當沒有足夠的空間可供擴展的時候,此時,原內存空間的大小維持不變。

  4、malloc函數的特殊情況

  如果mem_address為null,則realloc()和malloc()類似。分配一個newsize的內存塊,返回一個指向該內存塊的指針。

  如果newsize大小為0,那麽釋放mem_address指向的內存,並返回null。

  如果沒有足夠可用的內存用來完成重新分配(擴大原來的內存塊或者分配新的內存塊),則返回null而原來的內存塊保持不變。

  5、申請了內存空間後,必須檢查是否分配成功

  6、當不需要再使用申請的內存時,記得釋放;釋放後應該把指向這塊內存的指針指向NULL,防止程序後面不小心使用了它。

  7、這兩個函數應該是配對。如果申請後不釋放就是內存泄露;如果無故釋放那就是什麽也沒有做。釋放只能一次,如果釋放兩次及兩次以上會出現錯誤(釋放空指針例外,釋放空指針其實也等於啥也沒做,所以釋放空指針釋放多少次都沒有問題)。

  8、雖然malloc()函數的類型是(void *),任何類型的指針都可以轉換成(void *),但是最好還是在前面進行強制類型轉換,因為這樣可以躲過一些編譯器的檢查。

malloc()函數和free()函數的機制說明

malloc函數原理

  malloc()到底從哪裏分配到內存空間?答案是從堆裏面獲得空間。也就是說函數返回的指針是指向堆裏面的一塊內存。操作系統中有一個記錄空閑內存地址的鏈表。當操作系統收到程序的申請時,就會遍歷該鏈表,然後就尋找第一個空間大於所申請空間的堆結點,然後就將該結點從空閑結點鏈表中刪除,並將該結點的空間分配給程序。關於堆的知識呢可以查詢數據結構方面的知識。在使用malloc()分配內存空間後,一定要記得釋放內存空間,否則就會出現內存泄漏。

free函數原理

  free()到底釋放了什麽?free()釋放的是指針指向的內存!註意!釋放的是內存,不是指針!指針並沒有被釋放,指針仍然指向原來的存儲空間。指針是一個變量,只有程序結束時才被銷毀。釋放了內存空間後,原來指向這塊空間的指針還是存在!只不過現在指針指向的內容的垃圾,是未定義的,所以說是垃圾。因此,釋放內存後把指針指向NULL,防止指針在後面不小心又被解引用了。free()的函數原型非常簡單,只有一個參數,只要把指向申請空間的指針傳遞給free()中的參數就可以完成釋放工作!這裏要追蹤到malloc()的申請問題了。申請的時候實際上占用的內存要比申請的大。因為超出的空間是用來記錄對這塊內存的管理信息。大多數實現所分配的存儲空間比所要求的要稍大一些,額外的空間用來記錄管理信息——分配塊的長度,指向下一個分配塊的指針等等。這就意味著如果寫過一個已分配區的尾端,則會改寫後一塊的管理信息。這種類型的錯誤是災難性的,但是因為這種錯誤不會很快就暴露出來,所以也就很難發現。將指向分配塊的指針向後移動也可能會改寫本塊的管理信息。

new運算符:

  動態創建對象時,只需指定其數據類型,而不必為該對象命名,new表達式返回指向該新創建對象的指針,我們可以通過指針來訪問此對象。

int *pi=new int;

  這個new表達式在堆區中分配創建了一個整型對象,並返回此對象的地址,並用該地址初始化指針pi 。

  動態創建的對象可以用初始化變量的方式初始化。

int *pi=new int(100); //指針pi所指向的對象初始化為100
string *ps=new string(10,’9’);//*ps 為“9999999999”

  如果不提供顯示初始化,對於類類型,用該類的默認構造函數初始化;而內置類型的對象則無初始化

也可以對動態創建的對象做值初始化:

int *pi=new int( );//初始化為0
int *pi=new int;//pi 指向一個沒有初始化的int
string *ps=new string( );//初始化為空字符串 (對於提供了默認構造函數的類類型,沒有必要對其對象進行值初始化)

delete運算符

  釋放指針指向的地址空間。

  delete p; //執行完該語句後,p變成了不確定的指針,在很多機器上,盡管p值沒有明確定義,但仍然存放了它之前所指對象的地址,然後p所指向的內存已經被釋放了,所以p不再有效。此時,該指針變成了懸垂指針(懸垂指針指向曾經存放對象的內存,但該對象已經不存在了)。懸垂指針往往導致程序錯誤,而且很難檢測出來。

  一旦刪除了指針所指的對象,立即將指針置為0,這樣就非常清楚的指明指針不再指向任何對象。(零值指針:int *ip=0;)

區分零值指針和NULL指針

  零值指針,是值是0的指針,可以是任何一種指針類型,可以是通用變體類型void*也可以是char*,int*等等。
  空指針,其實空指針只是一種編程概念,就如一個容器可能有空和非空兩種基本狀態,而在非空時可能裏面存儲了一個數值是0,因此空指針是人為認為的指針不提供任何地址訊息

new分配失敗時,返回什麽?

  1993年前,c++一直要求在內存分配失敗時operator new要返回0,現在則是要求operator new拋出std::bad_alloc異常。很多c++程序是在編譯器開始支持新規範前寫的。c++標準委員會不想放棄那些已有的遵循返回0規範的代碼,所以他們提供了另外形式的operator new(以及operator new[])以繼續提供返回0功能。這些形式被稱為“無拋出”,因為他們沒用過一個throw,而是在使用new的入口點采用了nothrow對象:

malloc與new的區別:

  1、new 返回指定類型的指針,並且可以自動計算所需要大小。而 malloc 則必須要由我們計算字節數,並且在返回後強行轉換為實際類型的指針

int* ptr 1= new int [100];  //返回類型為int*,分配大小為sizeof(int)*100字節;

int* ptr2 = (int *)malloc(100); //返回類型為void*,需要強制轉換為int*,分配大小為100字節;

  2、malloc 只管分配內存,並不能對所得的內存進行初始化,所以得到的一片新內存中,其值將是隨機的。除了分配及最後釋放的方法不一樣以外,通過malloc或new得到指針,在其它操作上保持一致。

有malloc/free為什麽還需要new/delete?

  1) malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用於申請動態內存和釋放內存。

  2) 對於非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由於malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free

  因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。註意new/delete不是庫函數

  我們不要企圖用malloc/free來完成動態對象的內存管理,應該用new/delete。由於內部數據類型的“對象”沒有構造與析構的過程,對它們而言malloc/free和new/delete是等價的。

  3) 既然new/delete的功能完全覆蓋了malloc/free,為什麽C++不把malloc/free淘汰出局呢?這是因為C++程序經常要調用C函數,而C程序只能用malloc/free管理動態內存。

  如果用free釋放“new創建的動態對象”,那麽該對象因無法執行析構函數而可能導致程序出錯。如果用delete釋放“malloc申請的動態內存”,結果也會導致程序出錯,但是該程序的可讀性很差。所以  new/delete必須配對使用,malloc/free也一樣。

malloc與new相關