最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語(yǔ)言動(dòng)態(tài)內(nèi)存管理示例詳解

 更新時(shí)間:2025年12月19日 08:58:55   作者:Yue丶越  
在C語(yǔ)言編程中,動(dòng)態(tài)內(nèi)存管理是一項(xiàng)核心技能,它允許程序在運(yùn)行時(shí)靈活地分配和釋放內(nèi)存,這篇文章主要介紹了C語(yǔ)言動(dòng)態(tài)內(nèi)存管理的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

在C語(yǔ)言編程中,靜態(tài)內(nèi)存分配(如數(shù)組、局部變量)受限于編譯時(shí)固定大小的特性,無(wú)法滿足程序運(yùn)行中動(dòng)態(tài)調(diào)整內(nèi)存的需求。動(dòng)態(tài)內(nèi)存管理則可通過(guò)malloc、calloc等函數(shù),可以讓我們自主申請(qǐng)和釋放內(nèi)存,以成為了靈活處理內(nèi)存需求的核心技術(shù)。本文我們將從基礎(chǔ)原理出發(fā),結(jié)合實(shí)戰(zhàn)案例,以帶你掌握動(dòng)態(tài)內(nèi)存管理的關(guān)鍵知識(shí)點(diǎn)。

一、為什么需要?jiǎng)討B(tài)內(nèi)存分配?

靜態(tài)內(nèi)存分配(如int arr[10] = {0})存在兩個(gè)核心局限:

  • 空間大小編譯時(shí)固定,無(wú)法根據(jù)運(yùn)行時(shí)數(shù)據(jù)(如用戶輸入)調(diào)整。
  • 數(shù)組聲明時(shí)必須指定長(zhǎng)度,一旦我們確定則無(wú)法修改。

而動(dòng)態(tài)內(nèi)存分配允許程序在運(yùn)行時(shí)根據(jù)需求申請(qǐng)內(nèi)存,用完后手動(dòng)釋放,極大提升了內(nèi)存使用的靈活性。例如處理用戶輸入的數(shù)組長(zhǎng)度、動(dòng)態(tài)存儲(chǔ)不確定數(shù)量的數(shù)據(jù)時(shí),動(dòng)態(tài)內(nèi)存是我們唯一的選擇。

二、動(dòng)態(tài)內(nèi)存核心函數(shù)

C語(yǔ)言提供了4個(gè)核心動(dòng)態(tài)內(nèi)存函數(shù),它們均聲明在stdlib.h頭文件中,各自適用場(chǎng)景不同,我們?cè)谶\(yùn)用時(shí)需精準(zhǔn)區(qū)分。

2.1 malloc

  • 函數(shù)原型
  • void* malloc(size_t size)

  • 功能:向堆區(qū)申請(qǐng)一塊連續(xù)的、大小為size字節(jié)的內(nèi)存,返回指向該內(nèi)存的指針。
  • 關(guān)鍵點(diǎn)
    • 申請(qǐng)成功返回非NULL指針,失敗返回NULL,必須檢查返回值。
    • 返回類型為void*,需強(qiáng)制轉(zhuǎn)換為目標(biāo)類型(如int*)。
    • 申請(qǐng)的內(nèi)存未初始化,內(nèi)容為隨機(jī)值。

示例代碼

#include <stdio.h>
#include <stdlib.h>

int main() {
    int num = 0;
    scanf("%d", &num);
    // 申請(qǐng)num個(gè)int大小的內(nèi)存
    int* ptr = (int*)malloc(num * sizeof(int));
    if (NULL != ptr) { // 檢查申請(qǐng)是否成功
        for (int i = 0; i < num; i++) {
            *(ptr + i) = 0; // 初始化內(nèi)存
        }
    }
    free(ptr); // 釋放內(nèi)存
    ptr = NULL; // 避免野指針
    return 0;
}

2.2 free

  • 函數(shù)原型
  • void free(void* ptr)

  • 功能:釋放ptr指向的動(dòng)態(tài)內(nèi)存(堆區(qū)),將內(nèi)存歸還給系統(tǒng)。
  • 致命誤區(qū)
    • 僅能釋放動(dòng)態(tài)內(nèi)存(malloc/calloc/realloc申請(qǐng)的內(nèi)存),釋放棧區(qū)內(nèi)存(如局部變量地址)會(huì)導(dǎo)致未定義行為。
    • ptr為NULL,free無(wú)任何操作,因此釋放后建議將指針置為NULL,避免“野指針”。

2.3 calloc

  • 函數(shù)原型
  • void* calloc(size_t num, size_t size)

  • 功能:申請(qǐng)num個(gè)大小為size字節(jié)的連續(xù)內(nèi)存,并將每個(gè)字節(jié)初始化為0。
  • 與malloc的核心差異calloc自動(dòng)初始化內(nèi)存,無(wú)需手動(dòng)賦值。若需申請(qǐng)“干凈”的內(nèi)存(如統(tǒng)計(jì)數(shù)組、初始值為0的緩存),calloc更高效。

示例代碼

int* p = (int*)calloc(10, sizeof(int)); 
if (NULL != p) {
    for (int i = 0; i < 10; i++) {
        printf("%d ", *(p + i)); // 輸出:0 0 0 0 0 0 0 0 0 0
    }
}
free(p);
p = NULL;

2.4 realloc

  • 函數(shù)原型

  • void* realloc(void* ptr, size_t size)

  • 功能:調(diào)整ptr指向的動(dòng)態(tài)內(nèi)存大小為size字節(jié),返回調(diào)整后的內(nèi)存起始地址。

  • 擴(kuò)容的兩種場(chǎng)景(核心點(diǎn)):

    • 場(chǎng)景1:原有內(nèi)存后有足夠空間:直接在原有內(nèi)存后追加空間,數(shù)據(jù)不移動(dòng),返回原地址。
    • 場(chǎng)景2:原有內(nèi)存后空間不足:在堆區(qū)新找一塊連續(xù)內(nèi)存,拷貝原數(shù)據(jù)到新地址,釋放原內(nèi)存,返回新地址。
  • 使用禁忌:禁止直接將返回值賦值給原指針(如ptr = realloc(ptr, 1000))。若擴(kuò)容失敗返回NULL,會(huì)導(dǎo)致原指針地址丟失,造成內(nèi)存泄漏。正確做法是先用臨時(shí)指針接收返回值,檢查成功后再賦值。

正確示例代碼

int* ptr = (int*)malloc(100);
if (NULL != ptr) {
    // 業(yè)務(wù)處理
}
// 擴(kuò)容:先存臨時(shí)指針
int* tmp = (int*)realloc(ptr, 1000); 
if (NULL != tmp) {
    ptr = tmp; // 擴(kuò)容成功,更新原指針
    // 后續(xù)業(yè)務(wù)處理
}
free(ptr);
ptr = NULL;

三、6個(gè)高頻動(dòng)態(tài)內(nèi)存錯(cuò)誤

動(dòng)態(tài)內(nèi)存錯(cuò)誤是C語(yǔ)言調(diào)試的重災(zāi)區(qū),以下6類錯(cuò)誤需重點(diǎn)規(guī)避,幾乎覆蓋了我們所有筆試/面試考點(diǎn)。

錯(cuò)誤類型錯(cuò)誤代碼示例后果
對(duì)NULL指針解引用int* p = (int*)malloc(INT_MAX/4); *p = 20;malloc失敗返回NULL,解引用會(huì)導(dǎo)致程序崩潰
越界訪問(wèn)int* p = (int*)malloc(10*sizeof(int)); for(i=0; i<=10; i++) *(p+i)=i;訪問(wèn)超出申請(qǐng)的內(nèi)存區(qū)域,破壞堆區(qū)數(shù)據(jù),導(dǎo)致程序異常
釋放非動(dòng)態(tài)內(nèi)存int a=10; int* p=&a; free(p);釋放棧區(qū)內(nèi)存,觸發(fā)未定義行為(程序崩潰或亂碼)
釋放部分動(dòng)態(tài)內(nèi)存int* p = (int*)malloc(100); p++; free(p);p不再指向內(nèi)存起始地址,free無(wú)法識(shí)別,導(dǎo)致內(nèi)存泄漏
重復(fù)釋放int* p = (int*)malloc(100); free(p); free(p);同一內(nèi)存被多次釋放,破壞堆區(qū)結(jié)構(gòu),程序崩潰
內(nèi)存泄漏void test(){int* p=(int*)malloc(100);}申請(qǐng)的內(nèi)存未釋放,程序運(yùn)行中內(nèi)存持續(xù)占用,最終耗盡

四、動(dòng)態(tài)內(nèi)存經(jīng)典筆試題

以下4道筆試題是企業(yè)面試高頻題,需結(jié)合內(nèi)存原理分析錯(cuò)誤根源。

題目1:指針傳值導(dǎo)致內(nèi)存泄漏

void GetMemory(char *p) { p = (char *)malloc(100); }
void Test(void) {
    char *str = NULL;
    GetMemory(str); // 傳值調(diào)用,p是str的副本
    strcpy(str, "hello world"); // str仍為NULL,解引用崩潰
    printf(str);
}

錯(cuò)誤原因GetMemory采用值傳遞,pstr的副本,malloc申請(qǐng)的內(nèi)存地址僅存于p,未傳遞給str。str始終為NULL,strcpy時(shí)解引用崩潰,且malloc的內(nèi)存未釋放,造成泄漏。

修正方案:改用指針的指針(char** p)傳址調(diào)用,將內(nèi)存地址賦值給*p

題目2:棧區(qū)內(nèi)存釋放后訪問(wèn)

char *GetMemory(void) {
    char p[] = "hello world"; // 棧區(qū)局部數(shù)組
    return p; // 返回棧區(qū)地址,函數(shù)結(jié)束后p被釋放
}
void Test(void) {
    char *str = NULL;
    str = GetMemory(); // str指向已釋放的棧區(qū)內(nèi)存
    printf(str); // 訪問(wèn)“野內(nèi)存”,輸出亂碼
}

錯(cuò)誤原因p是棧區(qū)局部數(shù)組,函數(shù)GetMemory結(jié)束后,棧區(qū)內(nèi)存被系統(tǒng)回收。str指向的地址已無(wú)效,訪問(wèn)時(shí)屬于“野內(nèi)存”操作,結(jié)果不確定。

修正方案:將p改為動(dòng)態(tài)內(nèi)存(char* p = (char*)malloc(12);),或用靜態(tài)數(shù)組(static char p[])。

題目3:正確傳址但未釋放內(nèi)存

void GetMemory(char **p, int num) { *p = (char *)malloc(num); }
void Test(void) {
    char *str = NULL;
    GetMemory(&str, 100); // 傳址調(diào)用,str獲得內(nèi)存地址
    strcpy(str, "hello");
    printf(str); // 輸出“hello”
}

潛在問(wèn)題malloc申請(qǐng)的內(nèi)存未用free釋放,程序結(jié)束前會(huì)造成內(nèi)存泄漏。

修正方案:在printf后添加free(str); str = NULL;。

題目4:釋放后仍訪問(wèn)野指針

void Test(void) {
    char *str = (char *)malloc(100);
    strcpy(str, "hello");
    free(str); // 釋放內(nèi)存,但str未置NULL
    if (str != NULL) { // 條件為真,錯(cuò)誤訪問(wèn)
        strcpy(str, "world"); // 寫入已釋放的內(nèi)存,破壞堆區(qū)
        printf(str);
    }
}

錯(cuò)誤原因free(str)后,內(nèi)存被歸還給系統(tǒng),但str仍指向原地址(野指針)。if條件誤判為“非空”,strcpy向已釋放的內(nèi)存寫入數(shù)據(jù),破壞堆區(qū)結(jié)構(gòu),可能導(dǎo)致程序崩潰。

修正方案free(str)后立即將str置為NULL(str = NULL;)。

五、柔性數(shù)組

C99標(biāo)準(zhǔn)允許結(jié)構(gòu)體的最后一個(gè)成員為“未知大小的數(shù)組”,稱為柔性數(shù)組,適用于需要“結(jié)構(gòu)體+動(dòng)態(tài)數(shù)組”連續(xù)內(nèi)存的場(chǎng)景。

5.1 柔性數(shù)組的定義

typedef struct st_type {
    int i; // 前面至少有一個(gè)其他成員
    int a[]; // 柔性數(shù)組成員(部分編譯器支持int a[0];)
} type_a;
  • 關(guān)鍵特性sizeof(type_a)僅計(jì)算非柔性成員的大?。ㄊ纠?code>sizeof(type_a) = 4,不包含a的內(nèi)存)。
  • 內(nèi)存申請(qǐng):需通過(guò)malloc分配“結(jié)構(gòu)體大小+柔性數(shù)組大小”的連續(xù)內(nèi)存,確保數(shù)組與結(jié)構(gòu)體在同一塊內(nèi)存中。

5.2 柔性數(shù)組的使用示例

#include <stdio.h>
#include <stdlib.h>

typedef struct st_type {
    int i;
    int a[]; // 柔性數(shù)組
} type_a;

int main() {
    // 申請(qǐng)“結(jié)構(gòu)體大小 + 100個(gè)int”的連續(xù)內(nèi)存
    type_a *p = (type_a*)malloc(sizeof(type_a) + 100 * sizeof(int));
    if (NULL != p) {
        p->i = 100; // 初始化非柔性成員
        for (int i = 0; i < 100; i++) {
            p->a[i] = i; // 操作柔性數(shù)組
        }
    }
    free(p); // 一次釋放所有內(nèi)存,包括柔性數(shù)組
    p = NULL;
    return 0;
}

5.3 柔性數(shù)組的優(yōu)勢(shì)

若用“結(jié)構(gòu)體+指針”(如下代碼)實(shí)現(xiàn)類似功能,柔性數(shù)組有兩大核心優(yōu)勢(shì):

// 對(duì)比方案:結(jié)構(gòu)體+指針
typedef struct st_type {
    int i;
    int *p_a; // 指針指向動(dòng)態(tài)內(nèi)存
} type_a;
  • 優(yōu)勢(shì)1:方便內(nèi)存釋放:柔性數(shù)組只需free(p)一次釋放所有內(nèi)存;而“結(jié)構(gòu)體+指針”需先釋放p->p_a,再釋放p,若用戶遺漏釋放p->p_a,會(huì)造成內(nèi)存泄漏。
  • 優(yōu)勢(shì)2:提升訪問(wèn)效率:柔性數(shù)組與結(jié)構(gòu)體在同一塊連續(xù)內(nèi)存中,CPU緩存命中率更高;而“結(jié)構(gòu)體+指針”的內(nèi)存是離散的(結(jié)構(gòu)體在一塊內(nèi)存,指針指向另一塊內(nèi)存),訪問(wèn)時(shí)需兩次尋址,效率更低。

六、C/C++程序內(nèi)存區(qū)域劃分:從內(nèi)核到棧區(qū)

理解內(nèi)存區(qū)域是掌握動(dòng)態(tài)內(nèi)存的基礎(chǔ),C/C++程序的內(nèi)存空間從高到低分為5個(gè)區(qū)域:

內(nèi)存區(qū)域存儲(chǔ)內(nèi)容生命周期管理方式
內(nèi)核空間操作系統(tǒng)內(nèi)核代碼/數(shù)據(jù)系統(tǒng)運(yùn)行期間操作系統(tǒng)管理
棧區(qū)(向下增長(zhǎng))局部變量、函數(shù)參數(shù)、返回值函數(shù)執(zhí)行期間編譯器自動(dòng)分配/釋放
內(nèi)存映射段動(dòng)態(tài)庫(kù)、文件映射隨進(jìn)程/庫(kù)加載/卸載系統(tǒng)管理
堆區(qū)(向上增長(zhǎng))動(dòng)態(tài)內(nèi)存(malloc/calloc等)程序員分配/釋放(或程序結(jié)束后OS回收)程序員手動(dòng)管理
數(shù)據(jù)段(靜態(tài)區(qū))全局變量、靜態(tài)變量(static程序運(yùn)行期間程序結(jié)束后系統(tǒng)釋放
代碼段函數(shù)二進(jìn)制代碼、只讀常量(如字符串字面量)程序運(yùn)行期間只讀,系統(tǒng)管理

關(guān)鍵區(qū)分:堆區(qū)與棧區(qū)的差異是高頻考點(diǎn)——棧區(qū)內(nèi)存自動(dòng)管理,大小有限(通常幾MB)。堆區(qū)內(nèi)存手動(dòng)管理,大小可至GB級(jí),是動(dòng)態(tài)內(nèi)存的核心區(qū)域。

掌握動(dòng)態(tài)內(nèi)存管理,不僅能解決實(shí)際開(kāi)發(fā)中的靈活內(nèi)存需求,更能深入理解C語(yǔ)言的內(nèi)存模型,為后續(xù)底層開(kāi)發(fā)(如操作系統(tǒng)、嵌入式)打下堅(jiān)實(shí)基礎(chǔ)。

至此,我們已梳理完“動(dòng)態(tài)內(nèi)存管理”的全部?jī)?nèi)容了。最后我們?cè)谖哪﹣?lái)進(jìn)行一個(gè)投個(gè)票,告訴我你對(duì)哪部分內(nèi)容最感興趣、收獲最大,也歡迎在評(píng)論區(qū)聊聊你的學(xué)習(xí)感受。

總結(jié)

到此這篇關(guān)于C語(yǔ)言動(dòng)態(tài)內(nèi)存管理的文章就介紹到這了,更多相關(guān)C語(yǔ)言動(dòng)態(tài)內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于C語(yǔ)言sprintf函數(shù)的深入理解

    基于C語(yǔ)言sprintf函數(shù)的深入理解

    本篇文章是對(duì)C語(yǔ)言中的sprintf函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++異常捕捉與處理的深入講解

    C++異常捕捉與處理的深入講解

    這篇文章主要給你大家介紹了關(guān)于C++異常捕捉與處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • C++ Log日志類輕量級(jí)支持格式化輸出變量實(shí)現(xiàn)代碼

    C++ Log日志類輕量級(jí)支持格式化輸出變量實(shí)現(xiàn)代碼

    這篇文章主要介紹了C++ Log日志類輕量級(jí)支持格式化輸出變量實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2019-04-04
  • 基于C語(yǔ)言實(shí)現(xiàn)http下載器

    基于C語(yǔ)言實(shí)現(xiàn)http下載器

    做OTA升級(jí)功能時(shí),我們能直接拿到的往往只是升級(jí)包的鏈接,需要我們自己去下載,這時(shí)候就需要用到http下載器。本文將利用C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的http下載器,感興趣的可以了解一下
    2022-12-12
  • C語(yǔ)言全面梳理文件操作方法

    C語(yǔ)言全面梳理文件操作方法

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的文件操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-05-05
  • C++?QT實(shí)現(xiàn)獲取本機(jī)網(wǎng)卡信息

    C++?QT實(shí)現(xiàn)獲取本機(jī)網(wǎng)卡信息

    這篇文章主要為大家詳細(xì)介紹了如何利用qt自帶的QNetworkInterface接口以及c++Iphlpapi庫(kù),獲取當(dāng)前windows電腦下的網(wǎng)卡信息,需要的可以參考下
    2024-01-01
  • C語(yǔ)言中的回調(diào)函數(shù)實(shí)例

    C語(yǔ)言中的回調(diào)函數(shù)實(shí)例

    如果函數(shù)A的指針作為函數(shù)B的參數(shù),在函數(shù)B中利用該指針調(diào)用函數(shù)A,則此時(shí)的A就是回調(diào)函數(shù)。
    2014-04-04
  • c語(yǔ)言實(shí)現(xiàn)的幾種常用排序算法

    c語(yǔ)言實(shí)現(xiàn)的幾種常用排序算法

    C,語(yǔ)言常用的排序方法有很多種。比如說(shuō)冒泡排序,直接交換排序,直接選擇排序,直接插入排序,二分插入排序,快速排序,歸并排序等等,下面這篇文章主要給大家介紹了關(guān)于c語(yǔ)言實(shí)現(xiàn)幾種常用的排序算法,需要的朋友可以參考下
    2021-06-06
  • C++字符數(shù)組的輸入輸出和字符串結(jié)束標(biāo)志使用講解

    C++字符數(shù)組的輸入輸出和字符串結(jié)束標(biāo)志使用講解

    這篇文章主要介紹了C++字符數(shù)組的輸入輸出和符串結(jié)束標(biāo)志使用講解,是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • Windows進(jìn)程崩潰問(wèn)題的定位方法

    Windows進(jìn)程崩潰問(wèn)題的定位方法

    這篇文章主要介紹了Windows進(jìn)程崩潰問(wèn)題的定位方法,本文使用nstd工具進(jìn)行進(jìn)程崩潰時(shí)內(nèi)存和堆棧轉(zhuǎn)儲(chǔ)的方法查明問(wèn)題所在,需要的朋友可以參考下
    2015-04-04

最新評(píng)論

西贡区| 孙吴县| 新民市| 昌图县| 南昌市| 辽源市| 阿城市| 尖扎县| 渭源县| 巴东县| 东莞市| 永丰县| 射阳县| 双鸭山市| 常宁市| 桃江县| 东山县| 碌曲县| 清新县| 乌拉特后旗| 洛扎县| 敦煌市| 望城县| 舟山市| 九寨沟县| 五莲县| 长阳| 花垣县| 泾源县| 沂水县| 乐至县| 丰县| 桂平市| 屯门区| 巴林左旗| 民县| 雅江县| 莎车县| 闽侯县| 凯里市| 浑源县|