C語言詳解:動(dòng)態(tài)內(nèi)存管理(含C99柔性數(shù)組)-創(chuàng)新互聯(lián)

1. 為什么存在動(dòng)態(tài)內(nèi)存分配

我們已經(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和free

C語言提供了一個(gè)動(dòng)態(tài)內(nèi)存開辟的函數(shù):

void* malloc (size_t size);

這個(gè)函數(shù)向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針。

  1. 如果開辟成功,則返回一個(gè)指向開辟好空間的指針

  1. 如果開辟失敗,則返回一個(gè)NULL指針(因此malloc的返回值一定要做檢查)

  1. 返回值類型是 void* ,所以malloc并不知道開辟空間的類型,由使用者自己來決定

  1. 如果參數(shù) size 為0,malloc的行為是未定義的

而C語言提供了另外一個(gè)函數(shù)free,用于動(dòng)態(tài)內(nèi)存的釋放和回收:

void free (void* ptr);
  1. 如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開辟的,則free函數(shù)的行為是未定義的

  1. 如果參數(shù) ptr 是NULL指針,則free函數(shù)什么事都不做

2.2 calloc

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 realloc

realloc函數(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ò)誤
  1. 對(duì)NULL指針的解引用操作

  1. 對(duì)動(dòng)態(tài)開辟空間的越界訪問

  1. 對(duì)非動(dòng)態(tài)開辟內(nèi)存使用free釋放

  1. 只釋放了一塊動(dòng)態(tài)開辟內(nèi)存的一部分

  1. 對(duì)同一塊動(dòng)態(tài)內(nèi)存重復(fù)釋放

  1. 動(dòng)態(tài)開辟內(nèi)存忘記釋放(內(nèi)存泄漏)

4. 柔性數(shù)組

柔性數(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)

微信小程序開發(fā)