為什么要有動態內存分配
? ? ? ? 我們在學習動態內存管理之前,一直都是通過開辟變量,或者是開辟數組的方式來在內存的棧區開辟空間的,但是這樣的開辟方式有局限性,因為一旦開辟之后,它們的大小就無法改變,就缺少了很多的靈活性,但是動態內存管理就可以幫助我們解決這個問題,它是在堆區開辟空間的,并且它所開辟的空間是可大可小的。
動態內存開辟四大函數
????????其實想要動態開辟內存空間非常的簡單,我們只需要學會內存開辟四大函數就可以了。
????????malloc和free
????????malloc函數就是用來在內存的堆區開辟空間的,它的函數定義如下。
? ?void* malloc (size_t size);
? ?函數的形參表示所要開辟空間的字節大小,你想要開辟幾個字節的空間,就給形參什么值,malloc函數是在堆區開辟的一塊連續的空間,一旦開辟了空間,我們想要找到這塊空間,就勢必要只要它的起始地址值,而malloc函數的返回值就是這個作用,它返回的是開辟空間的起始地址,那為什么是void*類型的指針呢?原因就是我在開辟的時候,我也不知道要往這塊空間里邊存放什么類型的數據,或者說什么類型的數據都可以存放在我這塊空間里邊,所以一開始就給它返回的是void*類型的指針。還有一個值得注意的點就是malloc開辟空間如果失敗的話,就會返回NULL值,所以我們需要對返回值進行判斷。
????????malloc函數的使用舉例
#include<stdio.h>
#include<stdlib.h>//四大內存開辟函數都需要包含這個頭文件int main()
{//假設現在我想要開辟40個字節的空間,并且像里邊存放整型數據int* pi = (int*)malloc(40);//判斷是否開辟成功//為NULL就代表開辟空間失敗,perror打印開辟失敗的原因//返回非0的值,C語言里邊返回非0的值表示異常結束if (pi == NULL){perror("malloc");return 1;}//開辟成功,可以向這塊空間里邊存值for (int i = 0; i < 10; i++){*(pi + i) = i + 1;//存入1~10的值}//打印for (int i = 0; i < 10; i++){printf("%d ", *(pi + i));}return 0;
}
? ? ? ? 由上邊的代碼跟運行結果來看,好像似乎并沒有什么問題,但malloc畢竟是動態開辟的空間,開辟了空間難道就不用回收的嗎?答案是要回收的,上邊的代碼好像并沒有回收,那怎么也可以運行呢,原因是當程序結束的時候,操作系統會自動幫你回收,不過如果日后的代碼過長,或者是程序是一個7*24小時不停歇的運轉的話,如果我們不主動回收,就會出現內存泄露的問題,所以如果這塊動態開辟的內存你不再想要使用的時候,就請主動回收掉,free函數就是用來主動回收的。
? ? ? ? free:
? ?它的函數定義如下
? ?void free (void* ptr);
? ?它的形參的指針就指向的是動態開辟的起始地址的位置,如果給它傳NULL,那么這個函數將什么都不會做。
? ?接下來我們對剛才的代碼做一個完善? ?
? ? ? ? 由圖可見,釋放代碼其實就兩行,但是至關重要。
? ? ? ? 大家可能會有疑惑,釋放完了空間之后,為什么還要將pi賦值為NULL指針,原因是因為剛才的pi指針接收了malloc動態開辟的空間,但是當free之后,剛才申請的那塊空間已經被釋放了,里邊的數據也已經不是剛才存進去的數據了,而此時pi指針里邊仍存放著那塊空間的地址,這就形成了野指針,所以給它賦值為NULL。
????????calloc和realloc
? ? ? ? calloc函數也是用來動態內存開辟空間的函數,它的函數定義如下
? ?void* calloc (size_t num,size_t size);
? ?函數的形參的意思就是為num個大小為size的元素開辟空間,并且calloc函數會把開辟的空間的每個字節都初始化為0。
????????calloc函數的使用舉例
#include<stdio.h>
#include<stdlib.h>
int main()
{//給10個大小為int類型的數據開辟空間//用malloc函數就相當于//malloc(10 * sizeof(int));int* pi = (int*)calloc(10, sizeof(int));if (pi == NULL){perror("calloc");return 1;}//開辟成功,使用//calloc會自動的給申請的空間初始化為0for (int i = 0; i < 10; i++){printf("%d ", *(pi + i));}//釋放free(pi);pi = NULL;return 0;
}
????????realloc函數是用來對我們動態申請的內存進行調整的。它的函數定義如下。
? ?void* realloc (void* ptr , size_t size);
? ?ptr是要調整空間內存的起始地址。size為調整之后的新大小。返回值為調整后的內存的起始位置。
? ? ? ? 對于realloc函數的重新調整空間大小,總共有三種情況。
? ? ? ? 情況1:原有空間之后有足夠的空間。
? ? ? ? 情況2:原有的空間之后沒有足夠的空間。
? ? ? ? 情況3:重新調整空間失敗,返回NULL指針。
????????realloc函數的使用舉例
#include<stdio.h>
#include<stdlib.h>
int main()
{//申請空間int* pi = (int*)malloc(40);if (pi == NULL){perror("malloc");return 1;}//使用空間for (int i = 0; i < 10; i++){*(pi + i) = i++;}for (int i = 0; i < 10; i++){printf("%d ", *(pi + i));}//內存不夠,重新調整//注意,這個返回值不能用剛才的pi來接收,因為可能開辟空間失敗返回NULL,這樣就導致原來開辟的空間也找不到了。int* ptr = (int*)realloc(pi, 80);if (ptr == NULL){perror("realloc");return 1;}else//開辟成功{pi = ptr;ptr = NULL;}//繼續使用........//釋放空間free(pi);pi = NULL;return 0;
}