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

邏輯上的分區(qū)

  • 棧區(qū)
  • 堆區(qū)
  • 靜態(tài)區(qū)
  • 常量區(qū)
  • 代碼區(qū)

代碼區(qū),常量區(qū),靜態(tài)區(qū),堆區(qū),棧區(qū)這個(gè)排列順序按照地址由小到大排列的

代碼區(qū):

只讀的

程序員無需對(duì)其操作,里邊放著代碼編譯之后形成的二進(jìn)制

常量區(qū):

只讀的

例如"acfun",'Q',5,等等的常量,放在常量區(qū)

char *p ="bilibili";

任何試圖修改常量區(qū)內(nèi)容的操作,都會(huì)造成內(nèi)存崩潰

char arr[] ="bilibili";
arr[0] = 'I';

在使用指針操作字符串的時(shí)候一定注意內(nèi)存分區(qū)的問題

strcpy(p, "123");
p[0] = 'I';
printf("%p\n",p);

靜態(tài)區(qū):

使用static關(guān)鍵字修飾的變量放在靜態(tài)區(qū)讨盒,放在靜態(tài)區(qū)的變量只被初始化一次

static int a = 10;
  • 如果不給初始值,默認(rèn)相當(dāng)于賦值0
static int b;//默認(rèn)相當(dāng)于給b = 0;
  • 使用static修飾的靜態(tài)變量生命周期等于整個(gè)程序的生命周期,即程序退出后才被釋放(iOS編程寫單例類的時(shí)候,要使用static)
int all = 10;//全局變量,實(shí)際上也放在靜態(tài)區(qū)

printf("%p\n",&a);//代碼區(qū),常量區(qū),靜態(tài)區(qū),棧區(qū),的所占空間并不大

printf("%p\n",&all);//里邊局部變量0x7fff5fbff7b0

printf("%p\n",&all);//外邊全局變量0x100001020

(Stack)棧區(qū):

一塊連續(xù)的內(nèi)存,由系統(tǒng)自動(dòng)分配和釋放,不需要程序員手動(dòng)管理,大小也就1M-2M

他是有自己管理的規(guī)則的:棧區(qū)內(nèi)存的分配按照先進(jìn)后出的原則

int a = 10;//先初始化的a
int b = 20;//后初始化的b

printf("%p\n",&a);//地址高
printf("%p\n",&b);//地址低

之前所學(xué)的代碼其實(shí)都放在棧區(qū),只不過沒有出現(xiàn)棧區(qū)溢出的問題

堆區(qū):

內(nèi)存比較大的空間都被堆區(qū)占用著,堆區(qū)是不連續(xù)的內(nèi)存空間,需要咱們程序員手動(dòng)的分配和釋放內(nèi)存

定義一個(gè)指針

int *p =malloc(4);

malloc就是程序員手動(dòng)分配內(nèi)存空間的函數(shù),函數(shù)的參數(shù)放著我們需要的內(nèi)存空間這塊空間就是堆內(nèi)存的一塊空間

printf("%p\n",p);//堆內(nèi)存地址
printf("%d\n",*p);//堆內(nèi)存里邊的值

釋放空間

free(p);
p = NULL;//讓p指向地址0x0.

課上練習(xí)

輸入三個(gè)單詞保存在堆內(nèi)存并輸出

   char *word[3] = {0};//指針數(shù)組
   char temp1[100] = {0};//用來保存每一個(gè)單詞
   printf("請(qǐng)輸入三個(gè)單詞:\n");
   for(int i = 0; i < 3; i++) {
       scanf("%s",temp1);
       
        word[i] =malloc(sizeof(temp1));//指向堆內(nèi)存地址
       
       strcpy(word[i], temp1);
    }
   printf("**********************\n");
   for(int i = 0; i < 3; i++) {
       printf("%s\n",word[i]);
       free(word[i]);//若多釋放一塊未開辟的空間,程序會(huì)崩潰掉,這種情況稱為過度釋放
        word[i] =NULL;
    }

內(nèi)存分配函數(shù)

malloc和free…這些函數(shù)維護(hù)一個(gè)可用內(nèi)存池斩松,并向該程序返回一個(gè)指向這塊內(nèi)存的指針瞻凤。這塊內(nèi)存此時(shí)此刻并沒有以任何方式進(jìn)行初始化憨攒。如果這個(gè)內(nèi)存很重要你可以手動(dòng)進(jìn)行初始化,要么使用calloc函數(shù)阀参。

malloc函數(shù)

函數(shù)原型

void *malloc(size_t size);
  • size就是需要分配的內(nèi)存字節(jié)(字符)數(shù)肝集。如果內(nèi)存池中的內(nèi)存可以滿足這個(gè)要求,malloc就返回一個(gè)指向被分配內(nèi)存的起始位置的指針蛛壳。
  • malloc所分配的是一塊連續(xù)的內(nèi)存杏瞻。
  • 如果內(nèi)存池為空所刀,malloc函數(shù)會(huì)向操作系統(tǒng)請(qǐng)求。如果操作系統(tǒng)無法向malloc提供更多的內(nèi)存捞挥,malloc就會(huì)返回一個(gè)NULL指針浮创。因此要對(duì)malloc返回的指針進(jìn)行檢查,確保其非NULL
  • malloc返回一個(gè)void *的指針砌函。標(biāo)準(zhǔn)的void *指針可以轉(zhuǎn)換為其他任何類型的指針斩披。但是,在某些(老式)編譯器可能需要你在轉(zhuǎn)換時(shí)使用強(qiáng)制類型轉(zhuǎn)換
  • 對(duì)于要求邊界對(duì)齊的機(jī)器讹俊,malloc所返回的內(nèi)存的起始位置將始終能夠滿足對(duì)邊界對(duì)齊要求最嚴(yán)格的類型的要求垦沉。
char *p1 =malloc(4);
for(int i = 0; i < 4; i++) {
    *(p1+i) = 65 + i;
    printf("%c\n",*(p1+i));
}

free(p1);

p1 =NULL;

free函數(shù)

函數(shù)原型

void free(void *pointer);
  • free的參數(shù)要么是NULL,要么是先前從malloc仍劈、calloc或realloc返回的值厕倍。
  • 向free傳遞一個(gè)NULL參數(shù)不會(huì)產(chǎn)生任何效果

calloc函數(shù)

函數(shù)原型

void *calloc(size_t num_elements,size_t element_size);
  • calloc也用于分配內(nèi)存。malloc和calloc之間的主要區(qū)別是后者返回指向內(nèi)存的指針之前把它初始化為0贩疙。但顯得效率很低讹弯。
  • malloc和calloc它倆請(qǐng)求內(nèi)存數(shù)量的方式不同。calloc的參數(shù)包括所需元素的數(shù)量和每個(gè)元素的字節(jié)數(shù)屋群。根據(jù)這些值,可以計(jì)算出總共需要分配的內(nèi)存坏挠。
char *p2 =calloc(3, 1);第一個(gè)參數(shù)是分配多少個(gè),第二個(gè)參數(shù)是每個(gè)有多少個(gè)字節(jié)

for(int i = 0; i < 3; i++) {
    *(p2+i) = 'a';
    printf("%c\n",*(p2+i));
}

free(p2);

p2 =NULL;

練習(xí)

使用calloc函數(shù)分配十塊四個(gè)字節(jié)的空間,存放十個(gè)隨機(jī)數(shù)取值范圍在10 - 30之間,然后打印

char *p3 =calloc(10, 4);

for(inti = 0; i < 10; i++) {
    *(p3+i) =arc4random()%21 + 10;
    printf("%d\n",*(p3+i));
}

free(p3);

realloc函數(shù)

函數(shù)原型

void realloc(void *ptr,size_t new_size);
  • realloc函數(shù)用于修改一個(gè)原先已經(jīng)分配的內(nèi)存塊的大小芍躏。這個(gè)函數(shù)可以使一塊內(nèi)存擴(kuò)大或縮小。
  • 如果擴(kuò)大降狠,那么這塊內(nèi)存原先的內(nèi)容依然保留对竣,新增加的內(nèi)存添加到原先內(nèi)存塊的后面,新內(nèi)存并未以任何方法進(jìn)行初始化榜配。
  • 如果縮小否纬,該內(nèi)存塊尾部的部分內(nèi)存便被拿掉,剩余部分內(nèi)存的原先內(nèi)容依然保留蛋褥。
  • 如果原先的內(nèi)存塊無法改變大小临燃,realloc將分配另一塊正確大小的內(nèi)存,并把原先那塊內(nèi)存的內(nèi)容復(fù)制到新的塊上烙心。因此膜廊,在使用realloc之后,你就不能再使用指向舊內(nèi)存的指針淫茵,而應(yīng)該改用realloc所返回的新指針爪瓜。
  • 如果realloc函數(shù)的第一個(gè)參數(shù)是NULL,那么它的行為就和malloc一模一樣。
int *p4 =malloc(4);
int *p5 =realloc(p4, 8);給p4重新分配了8個(gè)字節(jié)的空間
  
*p5 = 10;
*(p5+1) = 20;

*p4 = 11;
*(p4+1) = 21;
  
printf("%d\n%d\n",*p5,*(p5+1));
printf("%d\n%d\n",*p4,*(p4+1));

memset內(nèi)存設(shè)置函數(shù)

int *p6 =malloc(4);

注意這里聲明的是整型

memset(p6, 65, 16);第一個(gè)參數(shù)放要操作的指針,第二個(gè)參數(shù)放內(nèi)容(整型或者字符型),第三個(gè)參數(shù)放字節(jié)數(shù)

for(inti = 0; i < 4; i++) {
printf("%c\n",*(p6+i));

}

memcpy內(nèi)存內(nèi)容拷貝的函數(shù)

char*p7 =malloc(4);

memcpy(p7, p6, 5);
 
for(inti = 0; i < 4; i++) {
//        *(p7 + i) = 66;
printf("%c\n",*(p7+i));
}

內(nèi)存的比較函數(shù)

跟字符串比較函數(shù)一樣,比較里邊的內(nèi)容,找到第一個(gè)不相同的字符,按照ascii碼表值進(jìn)行作差

int count =memcmp(p7, p6, 5);
printf("%d\n",count);

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

int *pi;
pi = malloc(100);
if(pi == NULL){
    printf("Out of memory!\n");
    exit(1);
}

如果分配內(nèi)存成功匙瘪,我們就擁有了一個(gè)指向100個(gè)字節(jié)的指針铆铆。在整型為4個(gè)字節(jié)的機(jī)器上蝶缀,這塊內(nèi)存將被當(dāng)作25個(gè)整型數(shù)組元素的數(shù)組,因?yàn)閜i是一個(gè)指向整型的指針薄货。

技巧

pi = malloc(25*sizeof(int));

常見動(dòng)態(tài)分配錯(cuò)誤

定義一個(gè)不易發(fā)生錯(cuò)誤的內(nèi)存分配器

#define malloc //防止由于其他代碼塊直接塞入程序而導(dǎo)致偶爾直接調(diào)用maloc的行為翁都。增加這個(gè)指令后,如果程序偶爾調(diào)用了malloc菲驴,程序?qū)⒂捎谡Z法錯(cuò)誤無編譯荐吵。
#define MALLOC(num,type) (type*)alloc((num)*sizeof(type))
extern void *alloc(size_t size);
  • 忘記檢查內(nèi)存是否分配成功
  • 被訪問的內(nèi)存可能保存了其他變量的值
  • 傳遞給free的指針必須是從malloc、calloc或realloc函數(shù)返回的指針赊瞬。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末先煎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子巧涧,更是在濱河造成了極大的恐慌薯蝎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谤绳,死亡現(xiàn)場(chǎng)離奇詭異占锯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)缩筛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門消略,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瞎抛,你說我怎么就攤上這事艺演。” “怎么了桐臊?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵胎撤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我断凶,道長(zhǎng)伤提,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任认烁,我火速辦了婚禮肿男,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘却嗡。我一直安慰自己次伶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布稽穆。 她就那樣靜靜地躺著冠王,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舌镶。 梳的紋絲不亂的頭發(fā)上柱彻,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天豪娜,我揣著相機(jī)與錄音,去河邊找鬼哟楷。 笑死瘤载,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卖擅。 我是一名探鬼主播鸣奔,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼惩阶!你這毒婦竟也來了挎狸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤断楷,失蹤者是張志新(化名)和其女友劉穎锨匆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冬筒,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恐锣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舞痰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片土榴。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖响牛,靈堂內(nèi)的尸體忽然破棺而出玷禽,到底是詐尸還是另有隱情,我是刑警寧澤娃善,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布论衍,位于F島的核電站瑞佩,受9級(jí)特大地震影響聚磺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜炬丸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一瘫寝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧稠炬,春花似錦焕阿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至毅桃,卻和暖如春褒纲,著一層夾襖步出監(jiān)牢的瞬間准夷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工莺掠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衫嵌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓彻秆,卻偏偏與公主長(zhǎng)得像楔绞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唇兑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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