內存相關函數

 

一、malloc可以知道函數原型是:

  Void *calloc(size_t  size) ,包含在庫函數 stdlib.h中,作用是在內存的堆區分配一個大小爲size的連續空間,如果分配內存成功,函數返回新分配內存的首地址,否則,返回NULL

malloc 向系統申請分配指定size個字節的內存空間。返回類型是 void* 類型。void* 表示未確定類型的指針。C,C++規定,void* 類型可以強制轉換爲任何其它類型的指針。

注意:鑑於上述這點,一般在寫程序需要判斷分配內存是否成功,如下程序語句:

  int  *p;

  p=(int *)malloc(sizeof(int));//

      memset(p,0,sizeof(int));//全部初始化爲0

  if(p!=NULL)

  .................................//需要執行的語句

  else

  .........................//打印分配內存不成功出錯信息

     free(p);

     p=NULL;

1.malloc 函數返回的是 void * 類型。對於C++,如果你寫成:p = malloc (sizeof(int)); 則程序無法通過編譯,報錯:“不能將 void* 賦值給 int * 類型變量”。所以必須通過 (int *) 來將強制轉換。而對於C,沒有這個要求,但爲了使C程序更方便的移植到C++中來,建議養成強制轉換的習慣。

2.函數的實參爲 sizeof(int) ,用於指明一個整型數據需要的大小。如果你寫成:

  int* p = (int *) malloc (1);

代碼也能通過編譯,但事實上只分配了1個字節大小的內存空間,當你往裏頭存入一個整數,就會有3個字節無家可歸,而直接“住進鄰居家”!造成的結果是後面的內存中原有數據內容被改寫。

3.malloc是必須指定內存大小的空間,比如想分配50個int類型的空間:int* p = (int *) malloc ( sizeof(int) * 50 ); //分配可以放得下50個整數的內存空間。

  通常造成內存分配失敗的原因如下:

  1、 內存訪問越界

  2、 所需連續的內存空間不足

 

二、realloc可以知道函數原型是:

    void *realloc(void *mem_address, unsigned int newsize);

     先按照newsize指定的大小分配空間,將原有數據從頭到尾拷貝到新分配的內存區域,而後釋放原來mem_address所指內存區域,同時返回新分配的內存區域的首地址。即重新分配存儲器塊的地址。他的作用就是重新申請內存空間,不影響原有數據,但是新分配的地址可能不一樣了。

     需要注意的:

    1、如果mem_address爲null,則realloc()和malloc()類似。分配一個newsize的內存塊,返回一個指向該內存塊的指針。如果沒有足夠可用的內存用來完成重新分配(擴大原來的內存塊或者分配新的內存塊),則返回null而原來的內存塊保持不變。 

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

    3、如果原來內存大小沒有足夠的空間來分配,那麼就會從堆棧中另找一塊指定大小的內存,並把原來的內存空間的內容複製歸來,返回心的mem_address指針,以前的被放回堆棧。

三、calloc函數原型是:

原型:extern void *calloc(int num_elems, int elem_size);
用法:#include <alloc.h>
功能:爲具有num_elems個長度爲elem_size元素的數組分配內存
說明:如果分配成功則返回指向被分配內存的指針,否則返回空指針NULL。


 

注意事項:

A、 申請了內存空間後,必須檢查是否分配成功。堆裏面獲得空間。也就是說函數返回的指針是指向堆裏面的一塊內存。操作系統 中有一個記錄空閒內存地址的鏈表。當操作系統收到程序的申請時,就會遍歷該鏈表,然後就尋找第一個空間大於所申請空間的堆結點,然後就將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序
B、當不需要再使用申請的內存時,記得釋放;釋放後應該把指向這塊內存的指針指向NULL,防止程序後面不小心使用了它。
C、這兩個函數應該是配對。如果申請後不釋放就是內存泄露;如果無故釋放那就是什麼也沒有做。釋放只能一次,如果釋放兩次及兩次以上會出現錯誤(釋放空指針例外,釋放空指針其實也等於啥也沒做,所以釋放空指針釋放多少次都沒有問題)。
D、雖然malloc()函數的類型是(void *),任何類型的指針都可以轉換成(void*),但是最好還是在前面進行強制類型轉換,因爲這樣可以躲過一些編譯器的檢查。
E、free()釋放的是指針指向的內存!注意!釋放的是內存,不是指針!這點非常非常重要!指針是一個變量,只有程序結束時才被銷燬。釋放了內存空間後,原來指向這塊空間的指針還是存在! 需要p=NULL 防止以後不小心用到

F、這個內存是隨機的 沒有被初始化。

1、calloc在動態分配完內存後,自動初始化該內存空間爲零,而malloc不初始化,裏邊數據是隨機的垃圾數據

2、realloc是給一個已經分配了地址的指針重新分配空間,參數ptr爲原有的空間地址,newsize是重新申請的地址長度

 

以下是C++專有的new 和delete

new用法:

          內部調用了malloc函數

          1.     開闢單變量地址空間

               1)new int;  //開闢一個存放數組的存儲空間,返回一個指向該存儲空間的地址.int *a = new int 即爲將一個int類型的地址賦值給整型指針a. 

               2)int *a = new int(5) 作用同上,但是同時將整數賦值爲5

          2.     開闢數組空間

               一維: int *a = new int[100];開闢一個大小爲100的整型數組空間

               二維: int **a = new int[5][6]

               三維及其以上:依此類推.

         一般用法: new 類型 [初值]

delete用法:

          1. int *a = new int;

               delete a;   //釋放單個int的空間

          2.int *a = new int[5];

               delete [] a; //釋放int數組空間

 

          要訪問new所開闢的結構體空間,無法直接通過變量名進行,只能通過賦值的指針進行訪問.

          用new和delete可以動態開闢,撤銷地址空間.在編程序時,若用完一個變量(一般是暫時存儲的數組),下次需要再用,但卻又想省去重新初始化的功夫,可以在每次開始使用時開闢一個空間,在用完後撤銷它.

注意:使用 new 得來的空間,必須用 delete 來釋放;使用 new [] 得來的空間,必須用 delete [] 來釋放。彼此之間不能混用。用 new [] 分配出連續空間後,指針變量“指向”該空間的首地址。

 

1.new、delete、malloc、free關係

delete會調用對象的析構函數,和new對應free只會釋放內存,new調用構造函數。malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用於申請動態內存和釋放內存。對於非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由於malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free。因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。

2.delete與 delete []區別

delete只會調用一次析構函數,而delete[]會調用每一個成員的析構函數。在More Effective  C++中有更爲詳細的解釋:“當delete操作符用於數組時,它爲每個數組元素調用析構函數,然後調用operatordelete來釋放內存。”delete與New配套,delete []與new []配套

  MemTest*mTest1=newMemTest[10];

  MemTest*mTest2=newMemTest;

  int*pInt1=newint[10];

  int*pInt2=newint;

  delete[]pInt1;  //-1-

  delete[]pInt2;  //-2-

  delete[]mTest1;//-3-

  delete[]mTest2;//-4-

  在-4-處報錯。

這就說明:對於內建簡單數據類型,delete和delete[]功能是相同的。對於自定義的複雜數據類型,delete和delete[]不能互用。delete[]刪除一個數組,delete刪除一個指針簡單來說,用new分配的內存用delete刪除用new[]分配的內存用delete[]刪除delete[]會調用數組元素的析構函數。內部數據類型沒有析構函數,所以問題不大。如果你在用delete時沒用括號,delete就會認爲指向的是單個對象,否則,它就會認爲指向的是一個數組。

 


發佈了51 篇原創文章 · 獲贊 23 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章