詳解C語言中動(dòng)態(tài)內(nèi)存管理及柔性數(shù)組的使用
一、malloc

這個(gè)函數(shù)向堆區(qū)申請一塊連續(xù)的空間,并返回這塊內(nèi)存的地址。
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
free(p);
p = NULL;
return 0;
}
如果開辟失敗,則返回一個(gè)NULL指針,因此malloc的返回值一定要做檢查。
如果參數(shù) size為0,malloc的行為是標(biāo)準(zhǔn)是未定義的,取決于編譯器。
二、free

free函數(shù)用來釋放動(dòng)態(tài)開辟的內(nèi)存。free的指針必須是指向動(dòng)態(tài)內(nèi)存空間的起始地址。
如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開辟的,那free函數(shù)的行為是未定義的。
如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。
三、calloc

num:要?jiǎng)討B(tài)開辟的元素個(gè)數(shù)
size:每個(gè)元素的大小

calloc=malloc+memset
calloc和malloc的區(qū)別就在于calloc會(huì)將動(dòng)態(tài)內(nèi)存開辟的空間全部初始化為0
四、realloc

ptr:需要擴(kuò)容的原始地址
size:擴(kuò)容后的總大小
1、realloc在擴(kuò)容時(shí)的情況
1、擴(kuò)容時(shí)后方空間足夠,將在后方繼續(xù)擴(kuò)容,返回原始地址
2、擴(kuò)容時(shí)后方空間已被使用,將在新的一塊區(qū)域進(jìn)行擴(kuò)容,并將原始數(shù)據(jù)拷貝至新的區(qū)域,free原始地址指向的內(nèi)存,并返回內(nèi)存塊的地址。
3、空間不足,無法擴(kuò)容,返回空指針
2、realloc也能實(shí)現(xiàn)malloc功能
int main()
{
int* p = (int*)realloc(NULL, 40);
return 0;
}
realloc在當(dāng)malloc使用時(shí),第一個(gè)參數(shù)傳空指針即可。
五、使用動(dòng)態(tài)內(nèi)存的常見錯(cuò)誤
1、free空指針
void text()
{
int* p = (int*)realloc(NULL, 40);
if (p == NULL)//判斷p是否為空指針
{
return;
}
*p = 20;
}
如果開辟空間后,沒有判斷指針p是否是空指針,如果動(dòng)態(tài)內(nèi)存開辟失敗,那么*p將會(huì)解引用空指針。
2、對動(dòng)態(tài)開辟的空間越界訪問
void text()
{
int* p = (int*)realloc(NULL, 40);
int* m = p;
if (p == NULL)
{
return;
}
for (int i = 0; i <= 10; i++)
{
p[i] = i;//越界
p++;
}
}
3、對非動(dòng)態(tài)開辟內(nèi)容free
void text()
{
int arr[] = {1,2,3};
int* p = arr;
free(p);//不能對非動(dòng)態(tài)開辟的空間進(jìn)行free
}
4、只free動(dòng)態(tài)開辟空間的一部分
void text()
{
int* p = (int*)malloc(40);
p++;
free(p);//p不再指向動(dòng)態(tài)開辟空間的起始位置
}
實(shí)際寫代碼的時(shí)候還是得多注意這種情況,指針p在使用的過程中已經(jīng)不再是初始位置,free(p)會(huì)崩潰。
5、對同一塊內(nèi)存多次free
void text()
{
int* p = (int*)realloc(NULL, 40);
free(p);
//p = NULL;
free(p);
}
free(p)后及時(shí)將p置為空指針,哪怕p被多次free也沒問題。
6、動(dòng)態(tài)內(nèi)存空間忘記釋放(內(nèi)存泄漏)
void text()
{
int* p = (int*)realloc(NULL, 40);
int a = 0;
scanf("%d", &a);
if (a == 5)
return;
free(p);
p = NULL;
}
當(dāng)函數(shù)提前終止,沒有機(jī)會(huì)走到free,可能會(huì)造成內(nèi)存泄漏
另一種可能是調(diào)用了動(dòng)態(tài)開辟內(nèi)存的函數(shù),使用者未在外部進(jìn)行free
六、柔性數(shù)組
1、柔性數(shù)組的概念
C99中,結(jié)構(gòu)體中最后一個(gè)成員變量可以是未知大小的數(shù)組
struct S
{
int a;
int arr[0];//這里的arr[0]代表未知大小的數(shù)組
};
//或者如下寫法:
struct S
{
int a;
int arr[];
};
2、柔性數(shù)組的特點(diǎn)
結(jié)構(gòu)體中的柔性數(shù)組成員前面必須至少一個(gè)其他成員。
sizeof 返回的這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存。
包含柔性數(shù)組成員的結(jié)構(gòu)用malloc ()函數(shù)進(jìn)行內(nèi)存的動(dòng)態(tài)分配,并且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小,以適應(yīng)柔性數(shù)組的預(yù)期大小。
3、柔性數(shù)組的使用場景
場景:將結(jié)構(gòu)體中所有的成員變量全部在堆區(qū)開辟
使用柔性數(shù)組:
struct S
{
int a;
int arr[0];
};
int main()
{
struct S s;
struct S* ps = &s;
ps = (struct S*)realloc(NULL,sizeof(s) + 40);//首次開辟空間,傳NULL
if (ps == NULL)
{
exit(-1);
}
free(ps);
ps = NULL;
return 0;
}
注意此處的realloc第一個(gè)參數(shù)傳入的是NULL而不是&s,傳入&s會(huì)崩潰,是因?yàn)檫@是第一次動(dòng)態(tài)內(nèi)存開辟,此處傳入NULL相當(dāng)于使用malloc
完成開辟后s在內(nèi)存中的存儲(chǔ)如下圖:

使用常規(guī)結(jié)構(gòu)體:
struct S
{
int a;
int* parr;
};
int main()
{
struct S* p = (struct S*)malloc(sizeof(struct S));//對結(jié)構(gòu)體動(dòng)態(tài)開辟空間
if (p == NULL)
{
exit(-1);
}
int* tmp= (int*)malloc(sizeof(int) * 2);//在堆區(qū)動(dòng)態(tài)開辟一塊空間
if (tmp == NULL)
{
exit(-1);
}
p->parr = tmp;
free(p->parr);//釋放時(shí),需要先釋放p->parr指向的空間
p->parr = NULL;
free(p);//再將結(jié)構(gòu)體指針p指向的空間釋放
p = NULL;
return 0;
}完成開辟后s在內(nèi)存中的存儲(chǔ)如下圖:

4、柔性數(shù)組的優(yōu)點(diǎn)
1、在上述條件下,使用柔性數(shù)組方便動(dòng)態(tài)內(nèi)存釋放。如果我們的代碼是在一個(gè)給別人用的函數(shù)中,你在里面做了二次內(nèi)存分配,并把整個(gè)結(jié)構(gòu)體返回給用戶。用戶調(diào)用free可以釋放結(jié)構(gòu)體,但是用戶并不知道這個(gè)結(jié)構(gòu)體內(nèi)的成員也需要free,可能會(huì)造成內(nèi)存泄漏。所以,如果我們把結(jié)構(gòu)體的內(nèi)存以及其成員要的內(nèi)存一次性分配好了,并返回給用戶一個(gè)結(jié)構(gòu)體指針,用戶做一次free就可以把所有的內(nèi)存給釋放掉。
2、連續(xù)的內(nèi)存有益于提高訪問速度,也有益于減少內(nèi)存碎片。
以上就是詳解C語言中動(dòng)態(tài)內(nèi)存管理及柔性數(shù)組的使用的詳細(xì)內(nèi)容,更多關(guān)于C語言 動(dòng)態(tài)內(nèi)存管理 柔性數(shù)組的資料請關(guān)注腳本之家其它相關(guān)文章!
- 深入了解C語言的動(dòng)態(tài)內(nèi)存管理
- C語言動(dòng)態(tài)內(nèi)存的分配最全面分析
- 一文帶你搞懂C語言動(dòng)態(tài)內(nèi)存管理
- 詳解C語言中的動(dòng)態(tài)內(nèi)存管理
- C語言動(dòng)態(tài)內(nèi)存分配圖文講解
- 使用c語言輕松實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存管
- 一文帶你了解C語言中的動(dòng)態(tài)內(nèi)存管理函數(shù)
- C語言動(dòng)態(tài)內(nèi)存管理的原理及實(shí)現(xiàn)方法
- 詳解C語言中動(dòng)態(tài)內(nèi)存管理
- C語言中常見的六種動(dòng)態(tài)內(nèi)存錯(cuò)誤總結(jié)
- 一文解析C語言中動(dòng)態(tài)內(nèi)存管理
- C語言動(dòng)態(tài)內(nèi)存管理的實(shí)現(xiàn)示例
相關(guān)文章
C++string底層框架模擬實(shí)現(xiàn)代碼
本節(jié)文章主要說明淺拷貝和深拷貝的優(yōu)缺點(diǎn),以及仿寫string類的邏輯并分析實(shí)現(xiàn)過程,對C++string底層框架模擬實(shí)現(xiàn)代碼感興趣的朋友一起看看吧2021-11-11
C++控制臺(tái)實(shí)現(xiàn)簡單注冊登錄
這篇文章主要為大家詳細(xì)介紹了C++控制臺(tái)實(shí)現(xiàn)簡單注冊登錄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
Cocos2d-x UI開發(fā)之CCControlPotentiometer控件類使用實(shí)例
這篇文章主要介紹了Cocos2d-x UI開發(fā)之CCControlPotentiometer控件類使用實(shí)例,本文代碼中包含注釋來講解CCControlPotentiometer控件類的使用,需要的朋友可以參考下2014-09-09
C語言實(shí)現(xiàn)簡單餐飲管理與點(diǎn)餐系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡單餐飲管理與點(diǎn)餐系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
C++利用棧實(shí)現(xiàn)中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式
這篇文章主要為大家詳細(xì)介紹了C++利用棧實(shí)現(xiàn)中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04

