記憶體動態分配

2021-05-02 12:40:11 字數 2999 閱讀 5921

陣列的元素儲存於記憶體中連續的位置上。當乙個陣列被宣告時,它所需要的內存在編譯時就被分配。但是,你也可以使用動態記憶體分配在執行時為它分配記憶體。

malloc所分配的是一塊連續的記憶體。例如,如果請求它分配100個位元組的記憶體,那麼它實際分配的記憶體就是100個連續的位元組,並不會分開位於兩塊或多塊不同的記憶體。同時malloc實際分配的記憶體有可能比你請求的稍微多一點。但是,這個行為是由編譯器決定的,所以你不能指望他肯定會分配比你的請求更多的記憶體。

如果記憶體池是空的,或者它的可用記憶體無法滿足你的要求。在這種情況下,malloc函式向作業系統請求,要求得到更多的記憶體,並在這塊新記憶體上執行分配任務。如果作業系統無法向malloc提供更多的記憶體,malloc就返回乙個null指標。因此,對每個malloc返回的指標都進行檢查,確保它並非null是非常重要的。

free的引數必須要麼是null,要麼是乙個先前從malloc、calloc或realloc返回的值。向free傳遞乙個null引數不會產生任何效果。

malloc返回乙個型別為void*的指標,正是源於這個原因。標準表示乙個void *型別的指標可以轉換為其他任何型別的指標。但是,有些編譯器,尤其是那些老式的編譯器,可能要求你在轉換時使用強制型別轉換。

對於要求邊界對其的機器,malloc所返回的記憶體的起始位置將始終能夠滿足對邊界對其要求最嚴格型別的要求。

calloc也用於記憶體分配。malloc和calloc之間的主要區別是後者在返回指向記憶體的指標之前把它初始化為0.這個初始化常常能帶來方便,但如果你的程式只是想把一些值儲存到陣列中,那麼這個初始化過程純屬浪費時間。calloc和malloc之間另乙個較小的區別是他們請求記憶體數量的方式不同。calloc的引數包括所需元素的數量和每個元素的位元組數。根據這些值,它能夠計算出總共需要分配的記憶體。

realloc函式用於修改乙個原先以及你給分配的記憶體塊的大小。使用這個函式,你可以使一塊記憶體擴大或縮小。如果它用於擴大乙個記憶體塊,那麼這塊記憶體原先的內容依然保留,新增加的記憶體新增到原先記憶體塊的後面,新記憶體並未以任何方式進行初始化。如果它用於縮小乙個記憶體塊,該記憶體塊尾部的部分記憶體便被拿掉,剩餘部分記憶體的原先內容依然保留。

如果原先的記憶體塊無法改變大小,realloc將分配另一塊正確大小的記憶體,並把原先那塊記憶體的內容複製到新的塊上。因此,在使用realloc之後,你就不能再使用指向舊記憶體的指標,而是應該用realloc所返回的新指標。

如果realloc函式的第乙個引數是null,那麼它的行為就和malloc一摸一樣。

常見的動態記憶體錯誤

在使用動態記憶體分配的程式中,常常會出現許多錯誤。這些錯誤包括對null指標進行解引用操作、對分配的記憶體進行操作時越過邊界、釋放並非動態分配的記憶體、試圖釋放一塊動態分配的記憶體的一部分以及一塊動態記憶體被釋放之後被繼續使用。

第一種錯誤顯而易見:被訪問的記憶體可能儲存了其他變數的值,對它進行修改將破壞那個變數,修改那個變數將破壞你儲存在那裡的值。這種型別的bug非常難以發現。(有時候bug可以理解為特性,只要你能把它管理好)

第二種問題不是那麼明顯。在malloc和free的有些實現中,它們以鍊錶的形式維護可用的記憶體池。對分配的記憶體之外的區域進行訪問可能破壞這個鍊錶,這有可能產生異常,從而終止程式。

一種不易發生錯誤的記憶體分配方案:

alloc.h

#include

#define malloc

#define malloc(num,type) (type *)alloc( (num) * sizeof(type))

extern void *alloc(size_t size);

alloc.c

#include

#include "alloc.h"

#undef malloc

void *

alloc(size_t size)

void *new_mem;

new_mem = malloc(size);

if(new_mem == null){

printf("out of memmory!/n")

return new_mem;

a_client.c

#include "alloc.h"

void

function()

int *new_memory;

new_memory = malloc(25,int);

free產生的錯誤

當使用free時,可能出現各種不同的錯誤。傳遞給free的指標必須是乙個從malloc、alloc或realloc函式返回的指標。傳給free函式乙個指標,讓它釋放一塊並非動態分配的記憶體可能導致程式立即終止或在晚些時候終止。試圖釋放一塊動態分配記憶體的一部分也有可能引起類似的問題。

釋放一塊記憶體的一部分是不允許的。動態分配的記憶體必須整塊一起釋放。但是,realloc函式可以縮小一塊動態分配的記憶體,有效的釋放它尾部的部分記憶體。

記憶體洩露

當動態分配的記憶體不再需要使用時,它應該被釋放,這樣它以後可以被重新分配使用。分配記憶體但在使用完畢後不釋放將引起記憶體洩露(memory leak)。在那些所有執行程式共享乙個通用記憶體池的作業系統中,記憶體洩露將以點點的榨乾可用記憶體,最終使其一無所有。要擺脫這個困境,只有重啟系統。

其他作業系統能夠記住每個程式當前擁有的記憶體段,這樣當乙個程式終止時,所有分配給他但未被釋放的記憶體都歸還給記憶體池。但即使在這類系統中,記憶體洩露仍然是乙個嚴重問題,因為乙個持續分配卻一點不釋放記憶體的程式最終將耗盡可用的記憶體。此時,這個有缺陷的程式將無法繼續執行下去,它的失敗有可能導致當前已經完成的工作統統丟失。

scanf的返回值

scanf("%d%d", &a, &b);

如果a和b都被成功讀入,那麼scanf的返回值就是2

如果只有a被成功讀入,返回值為1

如果a和b都未被成功讀入,返回值為0

如果遇到錯誤或遇到end of file,返回值為eof。

排序程式

動態分配記憶體

動態記憶體分配即分配記憶體大小在執行時才確定,一般在堆中分配。c語言動態記憶體分配相關的函式。include void malloc size t size malloc的使用比較直接,乙個成功的malloc呼叫返回分配的size大小的記憶體的指標。失敗時返回null並將錯誤 置為enomem。教材...

動態分配記憶體

動態分配記憶體 動態分配記憶體也可以分配儲存區,這種方式可以在程式執行的時候臨時決定分配的儲存區大小 為了管理動態分配的記憶體,就需要使用一組標準函式 為了使用這些標準函式,需要包含stdlib.h標頭檔案 malloc 函式可以動態分配一組連續的位元組 這個函式需要乙個整數型別引數表示分配的位元組...

動態分配記憶體

1 動態分配 new type 動態分配陣列 new type 釋放空間 delete expr 指標 釋放空間陣列 delete expr 2 new返回的是動態開的記憶體的首位址 如果沒有足夠的記憶體空間,其結果為乙個0值指標 int p new int 12 銷毀物件後,指標沒有定義,但是還指...