C語(yǔ)言內(nèi)存管理一本道來(lái)

動(dòng)態(tài)內(nèi)存分配



我們需要?jiǎng)討B(tài)內(nèi)存分配的原因

  • C語(yǔ)言中的一切操作都是基于內(nèi)存的
  • 變量和數(shù)組都是內(nèi)存的別名兵罢,如何分配這些內(nèi)存由編譯器在編譯期間決定
    • 定義數(shù)組的時(shí)候必須指定數(shù)組長(zhǎng)度
    • 而數(shù)組長(zhǎng)度是編譯器期就必須決定的

袍辞! 需求

程序運(yùn)行的過(guò)程中允悦,可能需要使用一些額外的內(nèi)存空間

malloc和free

動(dòng)態(tài)內(nèi)存分配.png
  • malloc所分配的是一塊連續(xù)的內(nèi)存挪鹏,以字節(jié)為單位,并且不帶任何的類型信息
  • free用與動(dòng)態(tài)歸還

注意

  • malloc實(shí)際分配的內(nèi)存可能會(huì)比請(qǐng)求的稍微多一點(diǎn)赘被,但是不能依賴于編譯器的這個(gè)行為
  • 當(dāng)請(qǐng)求的動(dòng)態(tài)內(nèi)存無(wú)法滿足時(shí)malloc返回NULL
  • 當(dāng)free參數(shù)為NULL時(shí)候衰伯,函數(shù)直接返回

calloc和realloc

  • void* calloc(size_t num,size_t size)(單元的數(shù)量,單元的大惺濉)
  • void* realloc(void* pointer,size_t new_size)(指向之前已經(jīng)分配的內(nèi)存新的內(nèi)存需要的內(nèi)存)重置動(dòng)態(tài)內(nèi)存空間的大刑枰健)

程序的三個(gè)要素

后進(jìn)先出

  • 棧是現(xiàn)代計(jì)算機(jī)程序最為重要的概念之一
  • 棧在程序中用于維護(hù)函數(shù)的調(diào)用上下文,沒(méi)有棧就沒(méi)有函數(shù)算色,沒(méi)有局部變量
  • 棧保存了一個(gè)函數(shù)調(diào)用所需要的維護(hù)信息
    • 函數(shù)參數(shù)抬伺,函數(shù)返回地址
    • 局部變量
    • 函數(shù)調(diào)用上下文
棧.png

tips:不能將一個(gè)指針指向一個(gè)局部變量

堆內(nèi)存需要主動(dòng)申請(qǐng)

  • 為什么有了棧還需要堆?
    • 棧上的數(shù)據(jù)在函數(shù)返回后就會(huì)被釋放掉灾梦,無(wú)法傳遞到函數(shù)外部峡钓,如局部變量
  • 堆是程序中一塊巨大的內(nèi)存空間,可由程序自由支配
  • 堆中被程序申請(qǐng)使用的內(nèi)存在程序主動(dòng)釋放前將一直有效
  • 系統(tǒng)對(duì)堆的管理方式
    • 空閑列表法若河,位圖法能岩,對(duì)象池法等等

程序的靜態(tài)存儲(chǔ)區(qū)

  • 程序的靜態(tài)存儲(chǔ)區(qū)隨著程序的運(yùn)行而分配空間,直到程序運(yùn)行結(jié)束
  • 在程序編譯期間靜態(tài)存儲(chǔ)區(qū)的大小就已經(jīng)確定
  • 程序的靜態(tài)存儲(chǔ)區(qū)主要用于保存程序中的全局變量和靜態(tài)變量
  • 與棧和堆不同萧福,靜態(tài)存儲(chǔ)區(qū)的信息最終會(huì)保存在可執(zhí)行程序中

小結(jié)

  • 棧拉鹃,堆和靜態(tài)存儲(chǔ)區(qū)是C語(yǔ)言常設(shè)計(jì)的三個(gè)基本區(qū)
  • 棧區(qū)是主營(yíng)帥帥函數(shù)的調(diào)用的使用
  • 堆區(qū)主要是用來(lái)內(nèi)存的動(dòng)態(tài)申請(qǐng)和歸還
  • 靜態(tài)存儲(chǔ)區(qū)用于保存全局變量和靜態(tài)變量

程序的內(nèi)存布局

  • 代碼在可執(zhí)行程序中的對(duì)應(yīng)位置
    • File Header告訴系統(tǒng)則是個(gè)可執(zhí)行的文件
    • data段用來(lái)存儲(chǔ)有初始化的數(shù)據(jù)
    • bss段用來(lái)存放沒(méi)有初始化的數(shù)據(jù)
    • text段是代碼段

程序文件的一般布局

程序文件的一般布局.png

程序的內(nèi)存布局(運(yùn)行的時(shí)候,由操作系統(tǒng)分配)

內(nèi)存布局.png

各個(gè)段的作用

  • 堆棧段在程序運(yùn)行后才正式存在鲫忍,是程序運(yùn)行的基礎(chǔ)(最先建立的原因是因?yàn)榛顒?dòng)進(jìn)程)
  • .bss段存放的是未初始化的全局變量和靜態(tài)變量
  • .text段存放的是程序中的可執(zhí)行的代碼
  • .dada段存放的是程序中已經(jīng)初始化的全局變量和靜態(tài)變量(必須要寫(xiě)到程序文件里面去)
  • .rodata段存放程序中的常量值毛俏,如字符串常量(只讀數(shù)據(jù)段)

.bss和.data段就是所謂的靜態(tài)存儲(chǔ)區(qū)

小結(jié)

  • 靜態(tài)存儲(chǔ)區(qū)指的是.bss和.data
  • 只讀區(qū)指的是.rodata
  • 局部變量所占用的空間為棧上空間
  • 動(dòng)態(tài)空間為堆空間
  • 程序可執(zhí)行代碼存放與.text段

頭疼的野指針(了解野指針)

  • 野指針通常是因?yàn)橹羔樧兞恐斜4娴闹?strong>不是一個(gè)合法的內(nèi)存地址而造成的
  • 野指針不是NULL,是一個(gè)指向不可用內(nèi)存的指針
  • NULL指針不容易弄錯(cuò)饲窿,可以通過(guò)if來(lái)判斷是否為NULL指針

C語(yǔ)言中沒(méi)有方法可以判斷是否為野指針

野指針的由來(lái)

  • 局部指針變量沒(méi)有被初始化例子1
  • 使用已經(jīng)釋放后的指針例子2
  • 指針?biāo)赶虻淖兞吭谥羔樦氨讳N毀例子3

最佳示例 例子1

#include <stdio.h>
#include <string.h>

struct Student
{
    char* name;
    int number;
};

int main()
{
    struct Student s;
    strcpy(s.name, "Delphi Tang"); // OOPS!
    s.number = 99;
    return 0;
}

最佳示例 例子2

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void func(char* p)
{
    printf("%s\n", p);
    free(p);
}

int main()
{
    char* s = (char*)malloc(5);
    strcpy(s, "Delphi Tang");
    func(s);
    printf("%s\n", s); // OOPS!
    return 0;
}

最佳示例

#include <stdio.h>
char* func()
{
    char p[] = "Delphi Tang";
    return p;
}

int main()
{
    char* s = func();
    printf("%s\n", s); // OOPS!
    return 0;
}

經(jīng)典的錯(cuò)誤(4野指針)

非法內(nèi)存操作分析

  • 結(jié)構(gòu)體成員指針沒(méi)有初始化
  • 沒(méi)有為結(jié)構(gòu)體指針?lè)峙渥銐虻膬?nèi)存

例子

#include<stdio.h>
#include<malloc.h>
struct Demo
{
    int * p;
};
void main()
{
    struct Dome d1;
    struct Dome d2;
    int i=0;
    for(i=0;i<10;i++)                     //問(wèn)題1:不能直接賦值煌寇,因?yàn)椴](méi)有分配內(nèi)存,也沒(méi)有初始化逾雄。
    {
        d1.p[i]=i+1;
    }
    free(d2.p);
    d2.p=(int *)calloc(5,sizeof(int));
    for(i=0;i<10;i++)                    //問(wèn)題2:只分配了5個(gè)空間阀溶,卻用了10個(gè)腻脏。
    {
        d2.p[i]=i+1;
    }
    free(d2.p);
    return 0;
}

內(nèi)存初始化分析

  • 內(nèi)存分配成功但是沒(méi)有初始化
#include<stdio.h>
#include<malloc.h>
void main()
{
    char* s=(char*)malloc(5);//不一定是 \0結(jié)束,所以不是字符串银锻。沒(méi)辦法輸出
    //s[4]='\0';
    printf(s);
    free(S);
}

內(nèi)存越界

  • 數(shù)組越界
void f(int a[10])
{
    int i=0;
    for(i=0;i<10;i++)
    {
        a[i]=i;
        printf("%d\n",a[i]);
    }
}
int main()
{
    int a[5];
    f(a);
    return 0;
}

內(nèi)存泄漏分析

#include <stdio.h>
#include <malloc.h>

void f(unsigned int size)
{
    int* p = (int*)malloc(size*sizeof(int));
    int i = 0;
    if( size % 2 != 0 )
    {
        return; // OOPS!需要free掉永品,基數(shù)個(gè)size的情況
    }
    for(i=0; i<size; i++)
    {
        p[i] = i;
        printf("%d\n", p[i]);
    }
    free(p);
}

int main()
{
    f(9);
    f(10);
    return 0;
}

C語(yǔ)言有關(guān)內(nèi)存的規(guī)則

用malloc申請(qǐng)了內(nèi)存之后,應(yīng)該立即檢查指針值是否為NULL击纬,防止使用值為NULL的指針

int *p=(int *)malloc(5*sizeof(int));
if(p!=NULL)
{

}
free(p);

牢記數(shù)組長(zhǎng)度鼎姐,防止數(shù)組越界操作,考慮使用柔性數(shù)組

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末更振,一起剝皮案震驚了整個(gè)濱河市炕桨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肯腕,老刑警劉巖献宫,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異实撒,居然都是意外死亡姊途,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)知态,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捷兰,“玉大人,你說(shuō)我怎么就攤上這事负敏」泵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵原在,是天一觀的道長(zhǎng)友扰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)庶柿,這世上最難降的妖魔是什么村怪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮浮庐,結(jié)果婚禮上甚负,老公的妹妹穿的比我還像新娘。我一直安慰自己审残,他們只是感情好梭域,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著搅轿,像睡著了一般病涨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上璧坟,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天既穆,我揣著相機(jī)與錄音赎懦,去河邊找鬼。 笑死幻工,一個(gè)胖子當(dāng)著我的面吹牛励两,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播囊颅,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼当悔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了踢代?” 一聲冷哼從身側(cè)響起盲憎,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奸鬓,沒(méi)想到半個(gè)月后焙畔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掸读,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡串远,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了儿惫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澡罚。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肾请,靈堂內(nèi)的尸體忽然破棺而出留搔,到底是詐尸還是另有隱情,我是刑警寧澤铛铁,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布隔显,位于F島的核電站,受9級(jí)特大地震影響饵逐,放射性物質(zhì)發(fā)生泄漏括眠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一倍权、第九天 我趴在偏房一處隱蔽的房頂上張望掷豺。 院中可真熱鬧,春花似錦薄声、人聲如沸当船。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)德频。三九已至,卻和暖如春缩幸,著一層夾襖步出監(jiān)牢的瞬間壹置,已是汗流浹背档叔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蒸绩,地道東北人衙四。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像患亿,于是被迫代替她去往敵國(guó)和親传蹈。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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