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