前言:本章將介紹4個常用的動態記憶體函式以及使用程序中的常見錯誤,
文章目錄
- 為什么需要動態記憶體分配?
- 我們已知的記憶體開辟方式:
- 已知開辟空間的方式有兩個缺點:
- 幾個動態記憶體函式的介紹
- malloc
- 示例程式:
- free
- 示例程式:
- calloc
- 示例程式:
- realloc
- 示例程式:
- 動態記憶體使用中的常見錯誤
- 1.未判斷指標是否為NULL,直接解參考(即對NULL指標解參考)
- 2.對動態開辟空間的越界訪問
- 3.對非動態開辟記憶體使用free釋放
- 4.過早使用free釋放掉一塊后期還需使用的動態記憶體
- 5.對同一塊動態記憶體多次釋放
- 6.動態開辟的記憶體忘記釋放(造成記憶體泄露)
為什么需要動態記憶體分配?
我們已知的記憶體開辟方式:
1.在堆疊空間上開辟4個位元組
int a=20;
2.在堆疊空間上開辟10個位元組的連續空間
char a[10]={0};
已知開辟空間的方式有兩個缺點:
1.空間開辟大小是固定的,
2.陣列在宣告的時候,必須指定陣列長度,它所需要的記憶體在編譯時已經分配,
但是有時候我們需要的空間大小在程式運行的時候才能知道,那陣列在編譯時開辟的空間可能無法滿足,這時候只能試試動態記憶體開辟了,
動態記憶體都是在堆中開辟的:

幾個動態記憶體函式的介紹
malloc
一個動態記憶體開辟的函式,原型如下:
void* malloc(size_t size);

這個malloc函式向記憶體申請一塊連續可用的空間,并回傳指向這塊空間的指標,有以下幾個特點:
如果開辟成功,則回傳一個指向開辟好空間的指標,
如果開辟失敗,則回傳一個NULL指標,因此malloc的回傳值一定要做檢查,
如果回傳值的型別是void*,那么malloc函式并不知道開辟空間的型別,具體由使用者決定,
如果引數size為0,malloc的行為是標準未定義的,取決于編輯器,
示例程式:
//假設開辟10個整形的空間 - 10* sizeof(int)
int arr[10];//堆疊區
//動態記憶體開辟的
int* p = (int*)malloc(10*sizeof(int));
if (ptr == NULL)
{
return 1;
}
for (i = 0; i < 10; i++)
{
printf("%d\n", *(p + i));
}
free(p);
p = NULL;
注釋:判斷指標是否為空是必須的!

free
專門用來做動態記憶體的釋放和回收的函式,原型如下:
void free(viod*ptr)
free函式用來釋放動態開辟的記憶體,
如果引數ptr指向的空間不是動態開辟的,那free函式的行為是未定義的,
如果引數ptr是NULL指標,則函式什么事都不做,
malloc和free都宣告在stdlib.h頭檔案,
示例程式:
int main()
{
int* ptr = (int*)malloc(sizeof(int) * 4);
if (ptr != NULL)
{
for (int i = 0; i < 4; i++)
{
ptr[i] = i;
printf("%d ", ptr[i]);
}
}
free(ptr);//思考這一步必須有嗎?
ptr = NULL;//思考這一步是必須的嗎?
return 0;
}
注釋:free(ptr);是必須的,因為malloc開辟出來的空間是在堆上,使用完一定要記得釋放否則就造成記憶體泄漏,ptr = NULL;也是必須的,因為ptr在free之后仍然指向開辟的空間,但開辟的空間已經還回去了,所以我們要手動置成NULL,
calloc
calloc函式也用動態記憶體分配,原型如下:
void* calloc(size_t num,size_t size);

為num個大小為size的元素開辟一塊空間,并且把空間的每個位元組初始化為0,
與函式malloc的區別在于calloc會在回傳地址之前把申請的空間的每個位元組初始化0.
示例程式:
int main()
{
int* p = calloc(10, sizeof(int));
if (p == NULL)
return 1;
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d\n", *(p + i));
}
free(p);
p = NULL;
return 0;
}

注釋:calloc開辟出來的空間也是在堆區上,使用完之后需要對記憶體進行釋放,同時也要判斷是否能開出了來,并置成NULL,
realloc
有時會我們發現過去申請的空間太小了,有時候我們又會覺得申請的空間過大了,需要對記憶體的大小做靈活的調整,而 realloc 函式就可以做到對動態開辟記憶體大小的調整,

函式原型如下:
void* realloc(void* ptr,size_t size);
其中引數ptr是要調整的記憶體地址,size為調整之后的大小,下面分析,realloc擴容是的兩種情況:
第一種:原空間后面有足夠大的空間


第二種:原空間后面沒有足夠大的空間


除此之外,當realloc所需開辟的記憶體過大開不,也是會回傳NULL,所以我們依舊要對回傳值進行判斷!
示例程式:
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (p == NULL)
{
perror("main");
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = 5;
}
//假設這里需要p指向的空間更大,需要20個int的空間
//realloc調整空間
int*ptr = (int*)realloc(p, 20*sizeof(int));
if (ptr != NULL)
{
p = ptr;
}
free(p);
p = NULL;
return 0;
}
動態記憶體使用中的常見錯誤
1.未判斷指標是否為NULL,直接解參考(即對NULL指標解參考)

2.對動態開辟空間的越界訪問

3.對非動態開辟記憶體使用free釋放
4.過早使用free釋放掉一塊后期還需使用的動態記憶體

5.對同一塊動態記憶體多次釋放

6.動態開辟的記憶體忘記釋放(造成記憶體泄露)

動態記憶體管理部分到此介紹結束了,感謝您的閱讀!!!如果內容對你有幫助的話,記得給我三連(點贊、收藏、關注)——做個手有余香的人,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290427.html
標籤:其他
