0x01為什么存在動態記憶體分配
我們已經掌握的記憶體開辟方式有:
int val=20;//在堆疊空間上開辟四個位元組 char arr[10]={0};//在堆疊空間上開辟10個位元組連續空間
但是上述的開辟空間方式有2個特點
1.空間開辟大小固定
2.陣列在宣告的時候,必須指定陣列長度,它所需要的記憶體在編譯時分配
但是對于空間的需求,不僅僅是上述的情況,有時候我們需要的空間大小在程式運行的時候才能知道,那陣列的編譯時開辟空間的方式就不能滿足了,這時候就要嘗試開辟動態記憶體
0x02動態記憶體函式介紹
malloc,calloc,realloc和free這4個函式
·malloc
void * malloc(size_t size);
這個函式向記憶體申請一塊連續可用的空間,并回傳指向這塊空間的指標,
1.如果開辟成功,則回傳一個指向開辟好空間的指標,
2.如果開辟失敗,則回傳一個NULL指標,因此malloc的回傳值一定要做檢查,
3.回傳值的型別時void *,所以malloc函式并不知道開辟空間型別,具體在使用的時候使用者自己來決定,
4.如果引數size為0,malloc的行為是標準是未定義的,取決于編輯器,
舉個列子
//記憶體申請10個整形空間 int *p = (int *)malloc(10 * sizeof(int)); if (p==NULL) { //列印錯誤 printf("%s", strerror(errno)); } else { for (size_t i = 0; i < 10; i++) { *(p + i) = i; printf("%d\r\n", *(p + i)); } }
·free
void free(void * ptr);
free函式專門用來做動態記憶體釋放和回收的
1.引數ptr指向的空間不是動態開辟的,那free函式的行為是未定義的
2.引數prt是NULL指標,則函式什么事都不做,
舉個例子
//記憶體申請10個整形空間 int *p = (int *)malloc(10 * sizeof(int)); if (p==NULL) { //列印錯誤 printf("%s", strerror(errno)); } else { for (size_t i = 0; i < 10; i++) { *(p + i) = i; printf("%d\r\n", *(p + i)); } } //當動態申請空間不在使用,應該還給作業系統 free(p);
但是實際上free(p)后的指標依然指向這些記憶體防止誤操作和記憶體泄漏這些記憶體應該讓p置空
//記憶體申請10個整形空間 int *p = (int *)malloc(10 * sizeof(int)); if (p==NULL) { //列印錯誤 printf("%s", strerror(errno)); } else { for (size_t i = 0; i < 10; i++) { *(p + i) = i; printf("%d\r\n", *(p + i)); } } //當動態申請空間不在使用,應該還給作業系統 free(p); p=NULL;//置空
·calloc
void * calloc(size_t num,size_t size);
1.函式功能是為num個大小為size的元素開辟一塊空間,并且把空間的每個位元組初始化為0;
2.與函式malloc的區別只在于calloc會在回傳地址之前把申請的空間每個位元組初始化為0
例如
int *p = (int *)calloc(10 , sizeof(int)); if (p==NULL) { //列印錯誤 printf("%s", strerror(errno)); } else { for (size_t i = 0; i < 10; i++) { //*(p + i) = i; printf("%d\r\n", *(p + i)); } }
malloc 效率高一點但是不初始化 和calloc各有千秋,
·realloc
void * realloc(void * ptr, size_t size);
1.realloc函式的出現讓記憶體管理更加靈活
2.有時候我們發現過去申請的空間太小了,有時候我們又覺得申請的空間過大了,為了合理的管理記憶體
對他們做調整,realloc函式客園做到對動態開辟記憶體大小做調整
3.ptr要調整的記憶體地址
4.size調整之后新大小
5.回傳值為調整后的記憶體起始位置
6.這個函式原記憶體空間大小基礎上,還會將原來記憶體中的資料移動到新的空間(改變地址)
7.realloc 在調整記憶體空間存在2種情況
7.1 原有空間足夠大 不需要重新開辟直接在原有基礎減少就好了
7.2 原有空間足夠大 需要重新開辟把原先存在的值復制到新的地址中
int *p = (int *)calloc(5 , sizeof(int)); if (p==NULL) { //列印錯誤 printf("%s", strerror(errno)); } else { for (size_t i = 0; i < 5; i++) { *(p + i) = i; } //申請40個空間 int *p2 = (int *)realloc(p, 40); for (size_t i = 5; i < 10; i++) { *(p + i) = i; } for (size_t i = 0; i < 10; i++) { printf("%d\r\n", *(p + i)); } } //當動態申請空間不在使用,應該還給作業系統 free(p);
當我們申請空間較小時運行可以看到

2個地址相同 代碼沒什么

可以看到回傳新地址了 它在后面地址地址不夠后 會選擇重新開辟空間
0x03常見的動態記憶體錯誤
1.對NULL指標解參考操作
void test() { int *p = (int *)malloc(10 * sizeof(INT_MAX)); *p = 20;//如果p的值是NULL,就會有問題 free(p);
}
2.對動態開辟空間越界訪問
void test() { int *p = (int *)malloc(10 * sizeof(int)); *p = 20;//如果p的值是NULL,就會有問題 if (p == NULL) { //列印錯誤 printf("%s", strerror(errno)); } for (size_t i = 0; i <=10; i++) { *(p + i) = i;//當等于10就會存在越界 } free(p); }
3.對非動態開辟記憶體使用free釋放
void test() { int a = 10; int *p = &a; free(p); }
4.使用free釋放一塊動態開辟記憶體的一部分
void test() { int *p = (int *)malloc(10 * sizeof(int)); p++; free(p);//p不再指向動態記憶體的起始位置 }
5.對同一塊動態記憶體多次釋放
int *p = (int *)malloc(10 * sizeof(int)); *p = 20;//如果p的值是NULL,就會有問題 if (p == NULL) { //列印錯誤 printf("%s", strerror(errno)); } free(p); p = NULL; free(p);
6.動態開辟記憶體忘記釋放(記憶體泄漏)
while(1) { malloc(1); sleep(1000); }
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/276092.html
標籤:其他
下一篇:整數轉羅馬數字Java版(力扣)
