C語言基礎(chǔ)及指針⑤動態(tài)內(nèi)存分配

接續(xù)上篇C語言基礎(chǔ)及指針④函數(shù)指針

在上一篇我們了解C語言中的函數(shù)及函數(shù)指針 , 使用函數(shù)指針 , 模擬了網(wǎng)絡(luò)請求的回調(diào)方式 , 今天我們來學(xué)習(xí)動態(tài)內(nèi)存分配。

我們在使用java的時候 , 所有的內(nèi)存都交由JVM做處理 , 我們無法直接控制 , 雖然很少導(dǎo)致內(nèi)存溢出 , 但是程序占用內(nèi)存卻會越來越大 , 所以我們在使用Android手機的時候 , 剛開始很流暢 , 用著用著就非常卡 , 在打開大文件或是播放gif的時候 , 如果采用java編寫處理引擎 , 則會比較卡 , 因為開辟的內(nèi)存空間無法控制 , GC回收又不是即時的 , 這時候就需要我們使用JNI技術(shù) , 使用C語言進行處理 。接下來 ,我們就來學(xué)習(xí)C語言中的動態(tài)內(nèi)存分配 。

C語言中內(nèi)存的大致分配:

內(nèi)存 描述 特性
棧區(qū) 是一個確定的常數(shù)(win 1~2M) 不同平臺會有不同大小 超出會提示stackoverflow 自動分配 , 自動釋放
堆區(qū) 用于動態(tài)內(nèi)存分配 手動分配和釋放 , 可占用80%內(nèi)存
全局區(qū)或靜態(tài)區(qū) 在程序中明確被初始化的全局變量、靜態(tài)變量(包括全局靜態(tài)變量和局部靜態(tài)變量)和常量數(shù)據(jù)(如字符串常量) 只初始化一次
程序代碼區(qū) 代碼區(qū)指令根據(jù)程序設(shè)計流程依次執(zhí)行,對于順序指令,則只會執(zhí)行一次(每個進程),如果反復(fù),則需要使用跳轉(zhuǎn)指令,如果進行遞歸,則需要借助棧來實現(xiàn)。 代碼區(qū)的指令中包括操作碼和要操作的對象(或?qū)ο蟮刂芬茫?/td>

C語言中動態(tài)分配內(nèi)存是在堆區(qū) , java語言中new一個對象 , 也會在堆內(nèi)存中開辟一塊空間 , 來存儲我們創(chuàng)建的這個對象 。在C語言中 , 我們在堆區(qū)開辟一塊空間使用的關(guān)鍵字是mallocmalloc函數(shù)定義:

void* __cdecl malloc(
    _In_ _CRT_GUARDOVERFLOW size_t _Size
    );

使用如下:

// 動態(tài)內(nèi)存分配 , 使用malloc函數(shù)在對內(nèi)存中開辟連續(xù)的內(nèi)存空間 , 單位是:字節(jié)
// 申請一塊40M的堆內(nèi)存
int* p = (int*)malloc(1024 *1024 * 10 * sizeof(int));

下面我們來模擬一下病毒:

/*動態(tài)內(nèi)存分配*/
void heapFunc() {
    // 動態(tài)內(nèi)存分配 , 使用malloc函數(shù)在對內(nèi)存中開辟連續(xù)的內(nèi)存空間 , 單位是:字節(jié)
    // 申請一塊40M的堆內(nèi)存
    int* p = (int*)malloc(1024 *1024 * 10 * sizeof(int));
}


void main() {

    while (1)
    {
        // 睡一秒執(zhí)行一次
        Sleep(1000);
        heapFunc();
    }

    getchar();

}

打開任務(wù)管理器 , 我們可以看到我們共存所占內(nèi)存 , 正在以40M每秒的速度 , 蹭蹭的往上漲 , 以前的蠕蟲病毒就是如此 , 不斷的消耗內(nèi)存 , 然后導(dǎo)致系統(tǒng)崩潰 。

在使用靜態(tài)內(nèi)存分配的時候 , 內(nèi)存大小是固定的 , 很容易超出棧內(nèi)存的最大值, 預(yù)估大小往往大大的超出使用大小 , 浪費內(nèi)存 。使用malloc申請內(nèi)存 , 最重要的一個點就是可以動態(tài)改變申請的內(nèi)存大小 , 可以使用realloc函數(shù)來重新申請內(nèi)存大小,realloc函數(shù)定義:

void* __cdecl realloc(
    _Pre_maybenull_ _Post_invalid_ void*  _Block,
    _In_ _CRT_GUARDOVERFLOW        size_t _Size
    );

使用如下:

// 重新申請內(nèi)存大小 , 傳入申請的內(nèi)存指針 , 申請內(nèi)存總大小
int* p2 = realloc(p, (len + add) * sizeof(int));

下面我們來應(yīng)用一下:

void main() {

    int len;
    printf("請輸入首次分配內(nèi)存大小:");
    scanf("%d", &len);
    // 動態(tài)分配內(nèi)存 , 內(nèi)存空間是連續(xù)的
    int* p = (int*)malloc(len * sizeof(int));
    // 給申請的內(nèi)存空間賦值
    int i = 0;
    for (; i < len ; i++)
    {    // 生成隨機數(shù)賦值
        p[i] = rand() % 100;

        printf("array[%d] = %d , %#x\n", i, p[i], &p[i]);
    }

    // 在原有內(nèi)存上面,重新分配內(nèi)存大小
    printf("請輸入增加的內(nèi)存大小");
    int add;
    scanf("%d", &add);
    // 重新申請內(nèi)存大小 , 傳入申請的內(nèi)存指針 , 申請內(nèi)存總大小
    int* p2 = (int*)realloc(p, (len + add) * sizeof(int));
    // 給新申請的內(nèi)存空間賦值
    int j = len;
    for (; j < len + add ; j++)
    {
        p2[j] = rand() % 200;
    
    }

    // 打印
    j = 0;
    for (; j < len + add; j++)
    {
        printf("array[%d] = %d , %#x\n", j, p2[j], &p2[j]);
    }
    
    // 回收申請的動態(tài)內(nèi)存
    if (p2 != NULL)
    {
        free(p2);
        p2 = NULL;
    }
        
    system("pause");
}

使用mallocrealloc配合 , 就可以模擬出我們java中的集合類型,動態(tài)改變內(nèi)存空間大小 。 使用malloc 第一次申請的內(nèi)存首地址和第二次申請的內(nèi)存首地址可能相同也可能不同 , 因為申請的內(nèi)存是連續(xù)的 , 所有 , 但第一次申請的空間的后續(xù)空間不夠用時 , 會重新開辟新的空間 , 并將數(shù)據(jù)copy到新的空間里面 。

內(nèi)存分配的幾個注意細(xì)節(jié):
1.不能多次釋放
2.釋放完之后 , 給指針置NULL,標(biāo)志釋放完成
3.內(nèi)存泄漏 (p重新賦值之后 , 再free , 并沒有真正釋放 , 要在賦值之前釋放前一個內(nèi)存空間)

Android程序員學(xué)C系列:
C語言基礎(chǔ)及指針①
C語言基礎(chǔ)及指針②之指針內(nèi)存分析
C語言基礎(chǔ)及指針③函數(shù)與二級指針
C語言基礎(chǔ)及指針④函數(shù)指針
C語言基礎(chǔ)及指針⑤動態(tài)內(nèi)存分配
C語言基礎(chǔ)及指針⑥字符操作
C語言基礎(chǔ)及指針⑦結(jié)構(gòu)體與指針
C語言基礎(chǔ)及指針⑧文件IO
C語言基礎(chǔ)及指針⑨聯(lián)合體與枚舉
C語言基礎(chǔ)及指針⑩預(yù)編譯及jni.h分析

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • C語言中內(nèi)存分配 在任何程序設(shè)計環(huán)境及語言中,內(nèi)存管理都十分重要。在目前的計算機系統(tǒng)或嵌入式系統(tǒng)中,內(nèi)存資源仍然是...
    一生信仰閱讀 1,193評論 0 2
  • (JG-2014-08-20)(前半部分經(jīng)過網(wǎng)上多篇文章對比整理)(后半部分根據(jù)ExceptionalCpp、C+...
    JasonGao閱讀 5,628評論 2 23
  • 前言 C語言作為一門應(yīng)用途廣泛、功能強大、使用靈活的面向過程式編程語言。既可用于編寫應(yīng)用軟件,又能用于編寫系統(tǒng)軟件...
    老板娘來盤一血閱讀 13,034評論 32 83
  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運用指針編程是C語言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu); ...
    朱森閱讀 3,473評論 3 44
  • 此刻,很慶幸還有那么一小段獨處時間給自己,借由“寫點什么”跟自己對對話,我喜歡這樣的方式,并保持了很多年。 今天醒...
    作家阿紫閱讀 243評論 0 0