我們已經(jīng)掌握的內(nèi)存開辟方式有:
創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括玄武網(wǎng)站建設(shè)、玄武網(wǎng)站制作、玄武網(wǎng)頁制作以及玄武網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,玄武網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到玄武省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!int val = 20;//在??臻g上開辟四個(gè)字節(jié)
char arr[10] = {0};//在??臻g上開辟10個(gè)字節(jié)的連續(xù)空間
上述的開辟空間的方式有兩個(gè)特點(diǎn):
1. 空間開辟大小是固定的。
2. 需要的內(nèi)存在編譯時(shí)分配
但是對(duì)于空間的需求,有時(shí)候在程序運(yùn)行的時(shí)候才能知道。
于是便有了動(dòng)態(tài)內(nèi)存分配,在堆區(qū)開辟內(nèi)存空間
2. 動(dòng)態(tài)內(nèi)存函數(shù)的介紹malloc,calloc,free,realloc函數(shù)都聲明在stdlib.h 頭文件中
2.1 malloc和freeC語言提供了一個(gè)動(dòng)態(tài)內(nèi)存開辟的函數(shù):
void* malloc (size_t size);
這個(gè)函數(shù)向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針。
如果開辟成功,則返回一個(gè)指向開辟好空間的指針
如果開辟失敗,則返回一個(gè)NULL指針(因此malloc的返回值一定要做檢查)
返回值類型是 void* ,所以malloc并不知道開辟空間的類型,由使用者自己來決定
如果參數(shù) size 為0,malloc的行為是未定義的
而C語言提供了另外一個(gè)函數(shù)free,用于動(dòng)態(tài)內(nèi)存的釋放和回收:
void free (void* ptr);
如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開辟的,則free函數(shù)的行為是未定義的
如果參數(shù) ptr 是NULL指針,則free函數(shù)什么事都不做
C語言還提供了一個(gè)函數(shù)叫 calloc ,也用于動(dòng)態(tài)內(nèi)存分配:
void* calloc (size_t num, size_t size);
函數(shù)的功能是為 num 個(gè)大小為 size 的元素開辟一塊空間
如果開辟成功,則返回一個(gè)指向開辟好空間的指針
如果開辟失敗,則返回一個(gè)NULL指針
與malloc的區(qū)別:
calloc會(huì)把空間的每個(gè)字節(jié)初始化為0
而malloc函數(shù)不會(huì)
舉個(gè)例子:
#include#includeint main()
{
? ? int *p = (int*)calloc(10, sizeof(int));
? ? if(NULL != p)
? ? {
? ? //使用空間
? ? }
? ? free(p);
? ? p = NULL;
? ? return 0;
}
因此,如果我們對(duì)申請(qǐng)的內(nèi)存空間的內(nèi)容要求初始化,就可以使用calloc函數(shù)來完成任務(wù)。
注意!malloc,calloc 都是在堆區(qū)上申請(qǐng)空間,空間使用完后都要釋放
2.3 reallocrealloc函數(shù)的出現(xiàn)讓動(dòng)態(tài)內(nèi)存管理更加靈活
有時(shí)候我們發(fā)現(xiàn)之前申請(qǐng)的空間太小了
為了合理使用內(nèi)存,我們一定會(huì)對(duì)內(nèi)存的大小做靈活的調(diào)整
而realloc 函數(shù)就可以對(duì)動(dòng)態(tài)開辟的內(nèi)存的大小進(jìn)行調(diào)整
void* realloc (void* ptr, size_t size);
ptr 是要調(diào)整的內(nèi)存地址
size 調(diào)整之后新大小
返回值為調(diào)整之后的內(nèi)存起始位置
注意!realloc在調(diào)整內(nèi)存空間的存在兩種情況:
1. 原空間后面有足夠大的空間
此時(shí),要擴(kuò)展內(nèi)存就直接在原有內(nèi)存之后追加空間,原空間的數(shù)據(jù)不發(fā)生變化
2. 原空間后面沒有足夠大的空間
此時(shí),要擴(kuò)展內(nèi)存,就會(huì)在堆空間上另找一個(gè)合適大小的連續(xù)空間來使用
原空間的數(shù)據(jù)會(huì)被拷貝到新空間中,并且原空間的內(nèi)存會(huì)被釋放
這樣函數(shù)返回的是一個(gè)新開辟空間的起始地址
由于上述的兩種情況,realloc函數(shù)的使用就要注意一些。
舉個(gè)例子:
#includeint main()
{
? ? //正常開辟動(dòng)態(tài)內(nèi)存
? ? int *ptr = (int*)malloc(100);
? ? if(ptr != NULL)
? ? {
? ? //...
? ? }
? ? else
? ? {
? ? exit(EXIT_FAILURE);
? ? }
? ? //下面要擴(kuò)展容量
? ? //代碼1
? ? ptr = (int*)realloc(ptr, 1000);//這樣可以嗎?
? ? //答:不行
? ? //正確做法
? ? int*p = (int*)realloc(ptr, 1000);
? ? if(p != NULL)
? ? {
? ? ? ? ptr = p;
? ? }
? ? //...
? ? free(ptr);
? ? return 0;
}
如上面代碼所示,我們先利用malloc正常開辟了100個(gè)字節(jié)的連續(xù)內(nèi)存空間,在判斷返回的指針非空之后,再進(jìn)行一系列使用。
這時(shí),我們想擴(kuò)展容量,需要用到realloc函數(shù)。
先看代碼1,我們想用上面接收malloc返回值的指針ptr來接受realloc的返回值,這時(shí)如果realloc開辟失敗,ptr將接收到realloc返回的一個(gè)空指針,此時(shí)我們就丟失了malloc開辟的內(nèi)存空間的地址,導(dǎo)致后面無法釋放malloc開辟的內(nèi)存,造成嚴(yán)重后果!
所以正確的做法是,另外定義一個(gè)指針變量p接收realloc的返回值,先判斷p是非空指針后,確認(rèn)了新空間已經(jīng)開辟,而realloc會(huì)自動(dòng)釋放舊空間,所以此時(shí)便可以大膽的將p的值賦給ptr,后續(xù)要釋放新空間的內(nèi)存時(shí),只需free(ptr)即可。
其實(shí),類似的注意事項(xiàng)和坑點(diǎn)還有很多,我們只需把握一個(gè)原則:
動(dòng)態(tài)開辟的內(nèi)存空間,最后一定要釋放,并且指針要置空!
而想要釋放內(nèi)存,便要保證存放該內(nèi)存地址的指針還存在!
釋放完內(nèi)存后,指針必須置空,防止非法訪問原先地址而擦寫數(shù)據(jù)!
3. 常見錯(cuò)誤對(duì)NULL指針的解引用操作
對(duì)動(dòng)態(tài)開辟空間的越界訪問
對(duì)非動(dòng)態(tài)開辟內(nèi)存使用free釋放
只釋放了一塊動(dòng)態(tài)開辟內(nèi)存的一部分
對(duì)同一塊動(dòng)態(tài)內(nèi)存重復(fù)釋放
動(dòng)態(tài)開辟內(nèi)存忘記釋放(內(nèi)存泄漏)
柔性數(shù)組(flexible array):
在C99 中,結(jié)構(gòu)體內(nèi)的最后一個(gè)元素允許是未知大小的數(shù)組,稱之為柔性數(shù)組成員
如下圖所示:
typedef struct s
{
? ? int i;
? ? int a[0];//柔性數(shù)組成員
}s;
有些編譯器可能會(huì)報(bào)錯(cuò),可以用下面方法表示:
typedef struct s
{
int i;
int a[];//柔性數(shù)組成員
}s;
那柔性數(shù)組有什么特點(diǎn)呢?
在結(jié)構(gòu)體中,柔性數(shù)組成員的前面至少有一個(gè)其他成員
利用sizeof 計(jì)算這種結(jié)構(gòu)體的大小時(shí),不包括柔性數(shù)組的內(nèi)存
例如:
又如:
顯然,利用sizeof 計(jì)算這種結(jié)構(gòu)體的大小時(shí),不包括柔性數(shù)組的內(nèi)存。
那么柔性數(shù)組該如何使用呢?
記住:
使用包含柔性數(shù)組成員的結(jié)構(gòu)體時(shí),要進(jìn)行動(dòng)態(tài)內(nèi)存分配
分配的內(nèi)存要大于結(jié)構(gòu)體的大小,從而適應(yīng)柔性數(shù)組的預(yù)期大小
#include#includetypedef struct s
{
int i;
int a[];//柔性數(shù)組成員
}s;
int main()
{
int i = 0;
s* p = (s*)malloc(sizeof(s) + 100 * sizeof(int));
p->i = 100;
for (i = 0; i< 100; i++)
{
p->a[i] = i;
}
for (i = 0; i< 100; i++)
{
printf("%2d ", p->a[i]);
}
printf("\n");
free(p);
p = NULL;
}
運(yùn)行結(jié)果如下:
這樣,柔性數(shù)組成員a,就獲得了100個(gè)整型元素大小的連續(xù)空間,可以使用。
又柔性數(shù)組的內(nèi)存是動(dòng)態(tài)分配的,因此如果對(duì)之前分配的內(nèi)存大小不滿意,則可以利用realloc函數(shù)進(jìn)行增容,例如:
#include#includetypedef struct s
{
int i;
int a[];//柔性數(shù)組成員
}s;
int main()
{
int i = 0;
s* p = (s*)malloc(sizeof(s) + 100 * sizeof(int));
s* ptr = (s*)realloc(p, sizeof(s) + 200 * sizeof(int));
if (ptr == NULL)
{
perror("realloc");
return 1;
}
//使用
//釋放
p = NULL;
free(ptr);
ptr = NULL;
return 0;
}
這樣,我們就將柔性數(shù)組a進(jìn)行了擴(kuò)容,獲得了200個(gè)整型元素大小的連續(xù)空間。
5. 結(jié)語通過本篇文章的學(xué)習(xí),我們掌握了C語言動(dòng)態(tài)內(nèi)存分配和C99中柔性數(shù)組的知識(shí)!
希望大家有所收獲,我們共同進(jìn)步!
感謝閱讀!
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
當(dāng)前標(biāo)題:C語言詳解:動(dòng)態(tài)內(nèi)存管理(含C99柔性數(shù)組)-創(chuàng)新互聯(lián)
文章源于:http://muchs.cn/article24/ceepje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名、小程序開發(fā)、品牌網(wǎng)站制作、靜態(tài)網(wǎng)站、軟件開發(fā)、移動(dòng)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容