內存分配(malloc()和free())


C語言的一個特性是接近底層,對於硬件的控制能力比其他高級動態語言要強。同時,C語言賦予程序員更大的自由度,更信任程序員。在內存的分配與釋放上,我們知道非靜態變量(塊作用域,無鏈接,自動生存期)在程序進入到變量定義所在的地方(塊或函數內)時分配內存,在離開塊作用域時釋放。對於靜態變量,在程序加載到內存時,變量的內存分配到靜態存儲區,且直到程序運行結束(終止)時釋放。這些都是程序執行過程中由程序自動控制的。
同時,C提供給程序員更大的權限,可以手動控制變量的內存分配和釋放,相關的函數為malloc(),calloc()和free()。

手動分配內存malloc()和calloc()

malloc():函數原型:void *malloc(size_t size),參數為要分配的內存字節數,返回值為指向void的指針,pointer-to-void,一般返回該段內存空間的首個字節。我們可以使用類型轉化將分配的內存起始地址賦值給一個指針變量,這樣我們就可以操作這段內存空間內的數據,並在必要時候釋放該段內存空間。
double * ptd;
ptd = (double *) malloc(30 * sizeof(double));
我們首先聲明一個指向double類型的指針變量ptd,然后使用malloc申請包含30個double類型的一段內存空間,並將其內存空間的起始地址賦值給ptd。我們甚至可以用變量n替換30這個常量,這樣相當於我們可以動態創建一個可變數組,類似VLA。若malloc分配內存失敗,則返回空指針NULL。


calloc()和malloc類似,函數原型為:void *calloc(size_t nitems, size_t size)。它有兩個參數,第一個為要申請的內存單元數,第二個為每個內存單元的字節數。malloc和calloc的區別在於calloc會將分配的這段內存里的每個元素設置為0(bit位為 0),相當於一個初始化的作用。

使用free() 釋放內存

一般使用malloc分配可一段內存空間后,需要在必要的時候手動釋放掉,以防止內存泄露。free()和malloc()配合使用。
示例:

/* dyn_arr.c -- dynamically allocated array */
#include<stdio.h>
#include<stdlib.h> /* for malloc(), free()  */

int main(void)
{
    double * ptd;
    int max = 0;
    int number = 0;
    int i = 0;

    puts("What is the maximum number of type double entries?");
    if (scanf("%d", &max) != 1)
    {
        puts("Number not correctly entered -- bye.");
        exit(EXIT_FAILURE);
    }
    ptd = (double *) malloc(max * sizeof(double));
    if (ptd == NULL)
    {
        puts("Memory allocation failed. Goodbye.");
        exit(EXIT_FAILURE);
    }
    /* ptd now points to an array of max elements */
    puts("Enter the values (q to quit):");
    while (i < max && scanf("%lf", &ptd[i]) == 1)
        ++i;
    printf("Here are your %d entries:\n", number = i);
    for (i = 0; i < number; i++)
    {
        printf("%7.2f ", ptd[i]);
        if (i % 7 == 6)
            putchar('\n');
    }
    if (i % 7 != 0)
        putchar('\n');
    puts("Done.");
    free(ptd);

    return 0;
}

輸出:
What is the maximum number of type double entries?
5
Enter the values (q to quit):
20 30 35 25 40 80
Here are your 5 entries:
20.00 30.00 35.00 25.00 40.00
Done.

雖然我們輸入了6個integer類型的數據,但實際輸出只有5個,因為我們申請的這段內存空間為包含5個integer類型的數組。

free()的重要性

若使用malloc或calloc手動分配內存,且沒有使用free釋放掉該段內存,某些操作系統會自動釋放掉這段內存,但不是所有的操作系統都支持這種特性。所以,不要依靠操作系統,而是要手動釋放掉這段內存。
原因:來看下面這段代碼:

int main()
{
    double glad[2000];
    int i;
    for (i = 0; i < 1000; i++)
        gobble(glad, 2000);
}

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

main函數每次調用gobble時,都會使用malloc手動申請2000個doube類型的內存空間,假設每個double類型占用8個字節(bytes)。那么執行到malloc處時,總共會申請16000字節的空間,而我們沒有調用free函數手動釋放掉這段內存空間,當該函數執行完畢時,指向這16000個字節空間的指針變量temp(塊作用域,無鏈接,自動生存期)將會消失,但這16000個字節的內存空間仍然存在,且程序無法通過任何變量或方式訪問該內存空間。
第二次調用gobble時,仍然會出現這種情況,直到for循環結束時,我們總共手動申請了1000 * 2000 * 8 = 16000000字節的內存空間,很有可能沒到這么多內存時,內存已經消耗完畢。這種情況,我們稱為內存泄漏。所以,我們要時刻記得使用free釋放掉malloc手動分配的內存空間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM