動態記憶體分配
文章目錄
- 動態記憶體分配
- 前言
- 一、malloc和free
- 1.malloc
- 2.free
- 二、calloc和realloc
- 1.calloc
- 2.realloc
- 三、記憶體泄漏
- 總結
前言
我們都知道,在存盤一些相同資料型別的元素時,我們會使用到陣列,但是,我們來考慮一種情況,當我們不知道元素個數時,如何指定陣列的大小呢,這種情況下,我們可能會指定一個較大的空間的陣列,因為其能容納更多的元素,
但是這么做同樣會有問題,比如說存盤的元素很少,就會造成大量陣列空間的浪費,但是如果把陣列空間設定的小一點來減少浪費,就有可能會出現陣列空間不夠用的情況了,這就是我們為何要使用動態記憶體分配,
一、malloc和free
C語言的函式庫提供了malloc和free兩個函式,分別用來執行動態記憶體的分配和釋放,這些函式維護一個可用的記憶體池,
1.malloc
當程式需要存盤資料時,它就呼叫malloc函式,從記憶體池中找到一塊合適的記憶體,同時回傳一個指向該記憶體的指標,
這塊分配的記憶體是沒有經過初始化的,若有初始化的要求,要么自己對其進行初始化,要么使用另外一個記憶體分配函式calloc(下面會講到)
下面是一個使用動態記憶體分配的例子:
代碼如下:
int* p;
int len = 10;
p = malloc(len * sizeof(int));
if (p == NULL)
{
exit(1);
}
malloc函式的引數是要分配記憶體的位元組數,如果記憶體池中的可用記憶體足夠,malloc就回傳一個指向起始位置的指標,其回傳值型別是一個void* 的指標,它可以轉換為任何其他型別的指標,
如果記憶體池是空的,或者說記憶體池空間不夠,malloc函式就會向作業系統請求得到更多的記憶體,并在新記憶體上執行分配任務,那如果作業系統無法向malloc函式提供記憶體,malloc函式就會回傳一個NULL指標,
So,在請求動態記憶體分配之后一定要檢查指標是否為空
2.free
那么,當我們使用完這塊記憶體之后不想再使用了,就要把它還給記憶體池以供接下來的使用,要把記憶體還回去就要呼叫free函式,
代碼如下:
int* p;
int len = 10;
p = malloc(len * sizeof(int));
if (p == NULL)
{
exit(1);
}
//釋放
free(p);
p = NULL;
free函式的引數要么是空指標,要么是之前從malloc、calloc和realloc回傳的值,給free函式傳遞一個空指標不會產生任何效果,
最后將p變成空指標是為什么呢?
當我們free掉動態分配的記憶體以后,這個指標指向的記憶體空間就會還給記憶體池,以供接下來的使用,但是此時我們的p指標依然指向的了這個位置,如果不把其置為空指標,就可能會對后來的使用產生影響,當這個位置分配給其他指標時,我們再去呼叫就會產生無法預計的后果,
同時free函式不能只釋放一部分的動態分配的記憶體,也不能釋放非動態分配的記憶體,同時要注意釋放之后的存盤不能再繼續使用了,
二、calloc和realloc
1.calloc
calloc函式也用于動態分配記憶體,malloc和calloc函式的區別主要是后者在回傳指向記憶體的指標之前將其初始化為0,如果你希望這樣初始化的話,就可以使用calloc函式,
另外一個小區別時,calloc函式的引數一個是元素的數量,一個是這種元素所對應的位元組數量,calloc函式可以自行計算出需要分配的記憶體大小,
代碼如下:
int* p;
int len = 10;
p = calloc(len, sizeof(int));
if (p == NULL)
{
exit(1);
}
2.realloc
如果動態分配的記憶體大小隨著我們的使用依然不夠了,要怎么辦呢?
realloc 函式用于修改一個原先已經分配的記憶體塊的大小,通過這個函式,可使已經分配的記憶體變大或者變小,
如果它用于擴大一個記憶體塊,那么原先的內容依舊保留,同時新增的記憶體添加到原先記憶體的后面,同時要注意,新記憶體是沒有初始化的,
如果它用于縮小一個記憶體塊,該記憶體塊尾部的相應大小就會被拿掉,剩余部分的記憶體保持不變,
如果原先的記憶體塊大小無法改變,realloc將分配另一塊正確大小的記憶體,并把原先的那塊記憶體的內容復制到新的記憶體塊上,
因此,在使用realloc之后,就不能再使用指向舊記憶體的指標了,而是應該使用realloc回傳的新指標,
如果realloc函式的第一個引數是NULL,那么它的作用就和malloc一模一樣,
代碼如下:
int* p;
int len = 10;
p = calloc(len, sizeof(int));
if (p == NULL)
{
exit(1);
}
int i = 0;
for (i = 0; i < len; i++)
{
scanf("%d", p + i);
}
len += len;
p = realloc(p, len * sizeof(int));
三、記憶體泄漏
當動態分配的記憶體不再需要時,應該被釋放,這樣它以后可以被重新分配使用,如果只分配記憶體,但是在使用完畢后不釋放將引起記憶體泄漏(memory leak),在那些所有執行程式共享一個通用的記憶體池的作業系統中,記憶體泄漏會一點一點的榨干可用記憶體,最終使其一無所有,
其他作業系統能夠記住每個程式當前擁有的記憶體段,這樣當一個程式終止時,所有分配給它但是未被釋放的記憶體都歸還給記憶體池,
但是在這種系統中,記憶體泄漏仍然是一個嚴重的問題,因為一個持續分配記憶體卻一點也不釋放記憶體的程式最終一定會耗盡所有可用記憶體,此時,這個有缺陷的程式將無法繼續執行下去,同時它的失敗可能會導致當前已經完成的作業統統丟失,
總結
malloc和calloc函式都用于動態分配一塊記憶體,并回傳一個指向該記憶體塊的指標,但是它們的引數不同malloc的引數是分配記憶體的位元組數,而calloc是元素個數和元素型別的大小,同時calloc可以將動態分配的記憶體初始化為0.
realloc函式可以改變一塊已經動態分配記憶體的大小
如果一個動態記憶體分配的記憶體塊不再使用,應及時呼叫free函式將其釋放,歸還給記憶體池,同時,釋放之后便不能再訪問,
若動態分配記憶體失敗,將會回傳NULL,同時應當注意不能越界訪問動態分配的記憶體,不能釋放非動態分配的記憶體、不能只釋放動態分配記憶體的一部分,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/382877.html
標籤:其他
下一篇:走進Linux(一切皆檔案)
