malloc函數詳解

函數定義及原理

函數定義

extern void *malloc(unsigned int num_bytes);//函數原型
#include<stdlib.h>//頭文件
void *malloc(size_t size);//函數聲明

原理

malloc函數接收一個參數:所需的內存字節數。malloc會根據這個參數找到合適的空閒內存塊,然後返回動態內存塊的首字節地址。這個內存塊是匿名的,malloc函數並不會爲其賦名。因此我們需要將該地址賦值給一個指針變量,然後通過指針變量來訪問這塊內存。

如果內存分配成功,malloc函數會返回一個(void*)類型的指針,在C、C++中規定該指針可以被強制轉換成任何類型的指針,因此malloc()函數可以用於返回指向數組的指針、指向結構的指針等而不用考慮類型匹配的問題。

如果內存分配失敗,則會返回空指針(NULL)。利用這個特性,我們必須在每次使用malloc函數後檢查內存是否分配成功。

使用malloc函數創建動態數組

double * ptd;
ptd = (double*)malloc(30 * sizeof(double));

這段代碼中,malloc函數爲30個double類型的值請求內存空間,然後使用強制類型轉換將返回的指針轉換成(double*)類型,然後賦值給ptd,即設置ptd指向所分配內存塊的首元素。回憶數組的定義,數組名即爲數組首元素的地址。我們將ptd指向內存塊的首元素,便可以像使用數組名一樣使用它。即用ptd[0]訪問內存塊的首元素,用ptd[1]訪問內存塊的第二個元素······

利用這個方法可以創建動態數組

double ptd[n];

通常我們執行程序時程序會報錯(C99後可以使用),因此我們可以使用以下方法來創建動態數組:

double *ptd = ptd = (double*)malloc( n * sizeof(double));

free函數

內存泄漏

在C語言中,通常把變量分爲靜態存儲變量和動態存儲變量兩類。靜態存儲變量是指在程序運行期間分配了固定存儲空間的變量;動態存儲變量是指在程序運行期間根據實際需要進行動態地分配存儲空間的變量。在內存中供用戶使用的內存空間分爲三部分:

  • 程序存儲區
  • 靜態存儲區
  • 動態存儲區

程序中使用的數據分別存放在靜態存儲區和動態存儲區中,靜態存儲區數據在程序的開始就分配好內存區。也就是說靜態內存的數量在編譯時時固定的,在程序運行期間也不會改變,在程序結束時自動釋放。但是動態內存的數量只會增加,除非使用free進行釋放。我們來看一段程序:

...
int main()
{
    double glad[2000];
    int i;
    ...
    for(int i=0;i<1000;i++)
        gobble(glad,2000);
    ...
}
void gobble(double ar[],int n)
{
    double * temp =(double*)malloc(n*sizeof(double));
}

在第一次調用gobble函數時,它創建了一個指針temp,併爲其分配了8*2000=16000字節的內存,在函數結束時,作爲自動變量的指針temp會消失,但是系統並不會爲我們自動釋放這16000字節的內存。因此這塊內存區域依舊存在,但由於temp指針已經消失,因此無法訪問這塊內存空間,同時它也無法被重複使用。

主函數多次調用了gobble函數,當for循環執行結束,程序總共調用了1000次gobble函數,也就造成了16000000字節的內存被佔用而無法使用,通常我們稱這類問題爲內存泄漏。爲了避免這類問題,我們需要在函數末尾使用free函數來釋放內存以避免這類問題的發生。

使用方法

free函數的參數是一個指針,即之前malloc函數返回的地址。使用時將其放在函數的末尾。例如上述代碼添加free函數:

void gobble(double ar[],int n)
{
    double * temp =(double*)malloc(n*sizeof(double));
    free(temp);
}

free函數使用的指針變量可以與malloc函數的指針變量不同,但是兩個指針變量必須儲存相同的地址。另外,如果被調函數使用malloc函數分配內存空間並返回指針供主調函數使用,則可以在主調函數末尾使用free函數通過該指針釋放被調函數創建的內存空間,也就是說內存塊可以在一個函數中創建,在另一個函數中銷燬。需要注意的是,不能釋放同一內存塊兩次。

其他相關函數的使用

calloc函數

calloc函數功能與malloc函數類似,其典型用法如下:

double * temp = (double *)calloc(1000,sizeof(double))

calloc函數的參數是兩個無符號整數,第一個參數是所需的存儲單元數量,第二個參數是每個存儲單元的大小。calloc函數有個特性,即在動態分配完內存後,自動初始化該內存空間爲零,而malloc不初始化,裏邊數據是隨機的垃圾數據。這是calloc與malloc最主要的區別。free函數也可以用於釋放calloc分配的內存空間。

realloc函數

當我們動態分配的內存不夠了或者過大,我們可以使用realloc函數來調整內存的大小。其基本語法爲:
=realloc() 指針名=(數據類型*)realloc(要改變內存大小的指針名,新的大小)
如果新的大小小於原內存大小,可能會導致數據的丟失;如果新的內存大小大於原內存大小,新分配的部分不會被初始化。

其原理時先判斷當前指針是否有足夠的連續內存空間,如果有則擴大當前地址,返回當前的指針;如果沒有,則根據指定的內存大小重新尋找並分配內存空間,然後將原有數據全部拷貝至新的內存塊,並自動釋放原來的內存,然後返回新的內存塊的首地址。

如果重新分配成功則返回指向被分配內存的指針,分配失敗則返回空指針(NULL)。在函數結束時同樣要使用free函數來釋放內存空間。

參考資料

  1. 百度百科"realloc"
  2. 百度百科"malloc"
  3. 《C Primer Plus》(第6版)中文版

更多文章請訪問我的個人博客網站 www.jbblogs.cn

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章