C语言-动态内存管理
C語言中,我們在使用數組的時候,經常有這樣的一個問題:數組在申明的時候,必須指定數組的長度,它所需要的內存在編譯時分配。有的時候,我們開辟的空間太小,無法滿足我們的需求,有時又太大,浪費空間比較嚴重。那么能不能按照需求,需要一個就開辟一個空間,需要兩個就開辟兩個空間? 這時候就只能試試動態內存開辟了。
一、malloc 函數和free 函數
C語言提供了一個用來動態開辟的函數:malloc函數。頭文件是stdlib.h。
void* malloc (size_t size);
該函數能夠在內存中申請一塊連續可用的空間,如果開辟成功,就返回這個開辟好空間的指針,否則,就返回NULL。因此,在使用malloc的時候,一定要對函數的返回值做檢查,避免空指針引用。由于malloc函數不知道要開辟的空間是什么類型,所以在使用的時候,一般要進行強制類型轉換。
free 函數是用來進行動態內存的釋放和回收的。頭文件是stdlib.h。
void free (void* ptr);
free函數只能對動態內存的函數進行釋放。如果不是指向的空間不是動態開辟的,那么free函數的結果都是未定義的。
#include<stdio.h>
#include<stdlib.h>
?
int main(void)
{
?? ?int* a = (int*)malloc(sizeof(int));//給a動態開辟空間
?? ?
?? ?free(a);
? ? a = NULL;
?? ?return 0;
}
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?給a申請空間
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?free(a)
?上面的例子只是單純的說明malloc函數的用法。要注意的是,一般情況下,一定要對malloc函數的返回值做檢查,同時,在使用完成malloc函數之后,要及時的進行釋放。同時,對引用的指針賦值為空。否則,上面的a就成為了野指針,在后面再次使用的時候就會導致出現非法訪問的問題。
二、calloc 函數
calloc 函數的功能是為 num 個大小為 size 的元素開辟一塊空間,并且把空間的每個字節初始化為0。與函數 malloc 的區別只在于 calloc 會在返回地址之前把申請的空間的每個字節初始化為全0。
void* calloc (size_t num, size_t size);
#include<stdio.h>
#include<stdlib.h>
?
int main(void)
{
?? ?int* p = (int*)calloc(10, sizeof(int));//給p動態開辟空間
?
?? ?free(p);
?? ?return 0;
}
三、realloc 函數
?
有的時候我們使用malloc函數之后,發現申請的空間還是太小,有的時候太大,想要再次進行修改,這個時候就可以使用realloc函數。頭文件是stdlib.h。
void* realloc (void* ptr, size_t size);
?ptr 是要調整的內存地址,size 是調整之后新大小。返回值是調整之后的內存的起始位置。
?
realloc函數進行調整的時候,有以下方式:
1,如果原有空間后面有足夠大的空間,就直接擴展。
2,另找一塊滿足要求的空間將原有空間的值進行拷貝,同時返回新的空間地址。
realloc函數的返回結果在使用時也要進行返回值是否為NULL的判斷。?
?
?四、常見的內存錯誤
1,對NULL指針解引用操作
#include<stdio.h>
#include<stdlib.h>
?
void test()
{
?? ?int* p = (int*)malloc(INT_MAX / 4);
?? ?if (p != NULL)
?? ?{
?? ??? ?*p = 20;//如果p的值是NULL,就會有問題,要進行判斷
?? ??? ?printf("%d", *p);//20
?? ?}
?? ?else
?? ?{
?? ??? ?printf("為空!");
?? ?}
?
?? ?free(p);
}
?
int main(void)
{
?? ?test();
?? ?return 0;
}
2,對動態開辟的空間越界訪問
void test()
{
?? ?int i = 0;
?? ?int* p = (int*)malloc(10 * sizeof(int));
?? ?if (NULL == p)
?? ?{
?? ??? ?exit(EXIT_FAILURE);
?? ?}
?? ?for (i = 0; i <= 10; i++)
?? ?{
?? ??? ?*(p + i) = i;//當i是10的時候越界訪問
?? ?}
?? ?free(p);
}
?
?
int main(void)
{
?? ?test();
?? ?return 0;
}
程序就會崩潰。
?
3,對非動態開辟的空間進行free釋放
void test()
{
?? ?int a = 10;
?? ?int* p = &a;
?? ?free(p);
}
?
int main(void)
{
?? ?test();
?
?? ?return 0;
}
?
?4,只釋放動態開辟內存的一部分
void test()
{
?? ?int* p = (int*)malloc(100);
?? ?p++;
?? ?free(p);//p不再指向動態內存的起始位置
}
?
int main(void)
{
?? ?test();
?
?? ?return 0;
}
結果同上。
5,多次釋放同一塊內存。
void test()
{
?? ?int* p = (int*)malloc(100);
?? ?free(p);
?? ?free(p);//重復釋放
}
?
int main(void)
{
?? ?test();
?
?? ?return 0;
}
還是同樣的結果。
6,忘記釋放,造成內存泄露。
void test()
{
?? ?int* p = (int*)malloc(100);
?? ?if (NULL != p)
?? ?{
?? ??? ?*p = 20;
?? ?}
}
int main()
{
?? ?test();
?? ?while (1);
}
動態內存的開辟是在堆上開辟的,這里面的內存需要自己手動來進行釋放,如果不釋放,在最后程序結束的時候可能由系統自動回收。
我們平時寫的變量等在棧,數據段(存放全局變量,靜態變量)等中,這些不需要手動釋放,他們有自己的作用域,出了這個作用域就會自動被銷毀。而在堆上開辟的空間需要手動來釋放。
?
總結
以上是生活随笔為你收集整理的C语言-动态内存管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LogBack 入门实践
- 下一篇: c语言-指针的本质和使用