malloc
malloc函數包含在頭文件#include<stdlib.h>中,這個函數在編寫代碼過程中是經常用到的常與結構體一起用。我們知道malloc參數的單位爲字節,並且他的返回值爲void*,如果它申請內存失敗,則會返回NULL。
當我們不知道某個變量需要多大的內存時,就可以使用malloc函數。
我們看下列代碼
int *a=(int*)malloc(sizeof(int));//int*是將void*強制轉換
*a = 6;
printf("%d\n",*a);
free(a);
打印結果我們都知道是6,但這個int型是通過申請動態內存而來的
值得注意的是,malloc函數所申請的內存,必須要通過free函數來釋放掉,否則極容易出現內存泄露問題
realloc
這個函數,估計大家沒見過幾次。它的作用是把一曾經已經申請到的內存進行擴容。
語法:指針名=(數據類型*)realloc(要改變內存大小的指針名,新的大小)。值得注意的是,新的大小要大於原來的內存大小,否則可能會出現數據丟失的情況,我們看個簡單的代碼
int *a=(int*)malloc(sizeof(int));
a = (int*)realloc(a,sizeof(int)*4);
free(a);
這裏原先a的大小爲4個字節,使用realloc函數後就把a的大小擴容成了16字節。
calloc
這個函數與malloc函數基本上沒有區別,值得注意的是他的格式爲:
int* ptr = (int *)calloc(10,sizeof(int));其中,calloc(10,sizeof(int))相當於malloc(sizeof(int )*10)
int *a=(int*)malloc(sizeof(int));
int* b = (int*)calloc(10,sizeof(int));
free(a);
free(b);
上述代碼中a,b的內存是一樣大的,還有一點就是calloc申請到的內存空間被初始化爲全0
上述三種申請的內存在 堆 這個內存上
如果一塊大的內存空間,也需要頻繁申請釋放,使用內存池,先從堆上申請一大塊內存,雖然現在可能只使用一小塊,未來需要使用其他內存的時候,就可以直接從池中使用,避免向系統進行申請。
除此之外我們看一下下面這個代碼
int a = 0;
int* b = &a;
free(b);
我們釋放了一個沒有通過動態內存申請的空間,這是錯誤的,相當於一個未定義行爲。要知道free只能釋放通過動態內存申請的內存。
int *a=(int*)malloc(sizeof(int));
free(a);
free(a);
申請的內存兩次釋放,這也是未定義行爲,第二次的釋放也相當於釋放一個不是通過動態內存所申請的內存。有些人可能會覺得不會寫兩次釋放,但是當你的代碼量非常大的時候,通過動態內存申請的地方非常多,如果不小心釋放了兩次,則會對程序造成很大的錯誤,所以一定要避免這樣的操作
柔性數組
這個知識點,大家可以瞭解瞭解
我們知道,一個數組的大小必須是要知道的,但是柔性數組可以不需要。首先要知道柔性數組必須要在結構體中才能使用,其次柔性數組成員前面必須有一個其他類型成員,最後必須是結構體最後一個成員
我們看如下代碼
struct stu{
int a;
char b;
int num[];
}stu;
這樣是正確的,相當於num就是一個長度可以動態變化的結構體成員,但是不能寫成如下形式
struct stu{
int a;
char b;
int num[];
int c;
}stu;
引入柔性數組可以更好的對內存進行釋放並且對其的訪問速度有一定的提升,還可以防止內存碎片的發生