動態記憶體分配函式 C 標準庫

2021-10-23 00:02:42 字數 3071 閱讀 2066

在c中我們開闢記憶體空間有兩種方式 :1.靜態開闢記憶體 : 例如:

int a;int b[10];

這種開闢記憶體空間的特點是

所開闢的記憶體是在棧中開闢的固定大小的 ,如a是4位元組 ,陣列b是40位元組 ,並且陣列在申明時必須指定其長度 , 因為陣列的記憶體是在編譯時分配好的 . 如果我們想在程式執行時才確定乙個陣列的大小 ,靜態開闢記憶體空間的方法是不行的 , 舉個例子 :

int n;scanf("%d", &n);int a[n];

這樣編寫會在編譯時出錯 , 編譯器會提醒[ ]中應為常量表示式 , 在c中定義陣列時可以用的有以下幾種 ,例:

#define n 10enum num;int a1[n];int a2[10];int a3[m];

需要注意的是 ,c中const int n =10 ; n並不能作為陣列長度定義陣列 , 但c++中則可以 , 

但我們對於開闢空間的需求 , 往往不限於此 , 最常見的定義陣列時陣列大小在程式執行時才知道的 , 靜態開闢就已經無能為力 . 當然有靜態開闢 ,肯定也有動態開闢 ,接下來我們就來看動態開闢記憶體空間

1.malloc()

void * malloc(size_t size)

1).malloc()函式會向堆中申請一片連續的可用記憶體空間2).若申請成功 ,,返回指向這片記憶體空間的指標 ,若失敗 ,則會返回null, 所以我們在用malloc()函式開闢動態記憶體之後, 一定要判斷函式返回值是否為null.3).返回值的型別為void*型, malloc()函式並不知道連續開闢的size個位元組是儲存什麼型別資料的 ,所以需要我們自行決定 ,方法是在malloc()前加強制轉 ,轉化成我們所需型別 ,如: (int*)malloc(sizeof(int)*n).4).如果size為0, 此行為是未定義的, 會發生未知錯誤, 取決於編譯器

具體怎麼用呢 ,舉個例子 .

int *p = null;int n = 0;scanf("%d", &n);p = (int*)malloc(sizeof(int) * n);if(p != null)

這時就相當於建立了乙個陣列 p[n] ,這個n的值並不需要像定義乙個普通陣列一樣必須是常量, 可以使程式執行時得出的, 或是使用者輸入的

2.free()

void free(void* ptr)

在堆中申請的記憶體空間不會像在棧中儲存的區域性變數一樣 ,函式呼叫完會自動釋放記憶體 , 如果我們不手動釋放, 直到程式執行結束才會釋放, 這樣就可能會造成記憶體洩漏, 即堆中這片記憶體中的資料已經不再使用, 但它一直佔著這片空間, (通俗說就是就是佔著茅坑不拉屎), 所以當我們申請的動態記憶體不再使用時 ,一定要及時釋放 .

1).如果ptr沒有指向使用動態記憶體分配函式分配的記憶體空間,則會導致未定義的行為。2).如果ptr是空指標,則該函式不執行任何操作。3).此函式不會更改ptr本身的值,因此它仍指向相同(現在已經無效)的位置(記憶體)4).在free()函式之後需要將ptr再置空 ,即ptr = null;如果不將ptr置空的話 ,後面程式如果再通過ptr會訪問到已經釋放過無效的或者已經被**再利用的記憶體, 為保證程式的健壯性, 一般我們都要寫ptr = null; . 

注意 : free()不能重複釋放一塊記憶體, 如:

free(ptr);free(ptr);

是錯的, 已經釋放過的記憶體不能重複釋放, 會出現記憶體錯誤 .

free()具體用法, 舉個例子 :

int *p = null;int n = 0;scanf("%d", &n);p = (int*)malloc(sizeof(int) * n);if(p != null)//操作完成 ,不再使用這片記憶體空間free(p);p = null;

3.calloc()

void * calloc(size_t num,size_t size)

與malloc()函式的區別只在於, calloc()函式會在返回位址之前將所申請的記憶體空間中的每個位元組都初始化為0 .

1).calloc()函式功能是動態分配num個大小(位元組長度)為size的記憶體空間 .2).若申請成功 ,,返回指向這片記憶體空間的指標 ,若失敗 ,則會返回null, 所以我們在用calloc()函式開闢動態記憶體之後, 一定要判斷函式返回值是否為null.3).返回值的型別為void*型, calloc()函式雖然分配num個size大小的記憶體空間 ,但還是不知道儲存的什麼型別資料 ,所以需要我們自行決定 ,方法是在calloc()前加強制轉 ,轉化成我們所需型別 ,如: (int*)calloc(num, sizeof(int)).4).如果size與num有乙個或都為0, 此行為是未定義的, 會發生未知錯誤, 取決於編譯器

所以如何我們對申請的記憶體空間的內容要求初始化,那麼可以很方便的使用calloc函式來完成這個需求。

例如 :

4.realloc()

void * realloc(void * ptr,size_t size)

realloc()函式讓動態記憶體管理更加靈活 .在程式執行過程中動態分配記憶體大小,  如果分配的太大 ,則浪費空間, 如果太小, 可能還是會出現不夠用的情況 .為了合理的利用記憶體,我們一定會對記憶體的大小做靈活的調整。那realloc() 函式就可以做到對動態開闢記憶體大小的調整(既可以往大調整, 也可以往小了調整) .

1).ptr為需要調整的記憶體位址2).size為調整後需要的大小(位元組數)3).若調整成功, 返回值為調整大小後記憶體的起始位置(也就是指向調整後記憶體的指標), 若失敗(當沒有記憶體可以分配時, 一般不會出現), 則返回null, 所以還是要對返回值判空4).如果ptr是空指標, 則和calloc()函式一樣作用一樣

注意 : realloc()函式在擴大記憶體空間時有兩種情況1).ptr所指的記憶體後有足夠的記憶體空間用來擴充套件 ,如圖 :

2).ptr所指記憶體後沒有足夠的空間來擴充套件 ,如圖 :

當第二種情況時, 若申請新的記憶體空間成功, 會將ptr所指向的記憶體中的內容拷貝到新的記憶體空間中, ptr所指向的記憶體會被釋放, 返回新得記憶體位址, 若不成功 ,ptr 所指記憶體不會被釋放, 函式返回null

5.小結

1).malloc()和calloc()函式用法一樣, 唯一的區別是calloc()會對所申請記憶體的每個位元組初始化為0

2).malloc(), calloc(), realloc()申請的記憶體不再使用時 ,一定要用free()釋放 ,否則會造成記憶體洩漏

c語言動態記憶體分配 C 動態記憶體分配

動態記憶體分配 雖然通過陣列就可以對大量的資料和物件進行有效地管理,但是很多情況下,在程式執行之前,我們並不能確切地知道陣列中會有多少個元素。這種情況下,如果陣列宣告過大,就會造成浪費 宣告過小,就會影響處理。在c 中,動態記憶體分配技術可以保證程式在執行過程中按照需要申請適量記憶體,使用後釋放,從...

C語言動態記憶體分配函式

目錄 1.malloc 2.free 3.calloc 4.realloc 5.小結 在c中我們開闢記憶體空間有兩種方式 1.靜態開闢記憶體 例如 int a int b 10 這種開闢記憶體空間的特點是 所開闢的記憶體是在棧中開闢的固定大小的 如a是4位元組 陣列b是40位元組 並且陣列在申明時必...

c 動態記憶體分配

c語言中提供的動態記憶體分配為了解決陣列的靜態的分配方式的問題 即陣列大小必須在定義時指定,程式在執行時不能動態改變陣列的大小 在標準庫中提供了三個動態記憶體分配的函式供程式呼叫,下面將分別對這三個函式進行介紹 1.void malloc size t size malloc 在分配一段連續的記憶體...