您好,登錄后才能下訂單哦!
這篇“C語(yǔ)言動(dòng)態(tài)內(nèi)存管理原理及實(shí)現(xiàn)的方法是什么”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“C語(yǔ)言動(dòng)態(tài)內(nèi)存管理原理及實(shí)現(xiàn)的方法是什么”文章吧。
我們已經(jīng)掌握的內(nèi)存開(kāi)辟方式有:
int val = 20;//在棧空間上開(kāi)辟四個(gè)字節(jié) char arr[10] = {0};//在??臻g上開(kāi)辟10個(gè)字節(jié)的連續(xù)空間
但是上述的開(kāi)辟空間的方式有兩個(gè)特點(diǎn):
空間開(kāi)辟大小是固定的。
數(shù)組在申明的時(shí)候,必須指定數(shù)組的長(zhǎng)度,它所需要的內(nèi)存在編譯時(shí)分配。
但是對(duì)于空間的需求,不僅僅是上述的情況。有時(shí)候我們需要的空間大小在程序運(yùn)行的時(shí)候才能知道,
那數(shù)組的編譯時(shí)開(kāi)辟空間的方式就不能滿(mǎn)足了。
這時(shí)候就只能試試動(dòng)態(tài)存開(kāi)辟了。
C語(yǔ)言提供了一個(gè)動(dòng)態(tài)內(nèi)存開(kāi)辟的函數(shù):
void* malloc (size_t size);
這個(gè)函數(shù)向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針。
如果開(kāi)辟成功,則返回一個(gè)指向開(kāi)辟好空間的指針。
如果開(kāi)辟失敗,則返回一個(gè)NULL指針,因此malloc的返回值一定要做檢查。
返回值的類(lèi)型是 void* ,所以malloc函數(shù)并不知道開(kāi)辟空間的類(lèi)型,具體在使用的時(shí)候使用者自己來(lái)決定。
如果參數(shù) size 為0,malloc的行為是標(biāo)準(zhǔn)是未定義的,取決于編譯器。
C語(yǔ)言提供了另外一個(gè)函數(shù)free,專(zhuān)門(mén)是用來(lái)做動(dòng)態(tài)內(nèi)存的釋放和回收的,函數(shù)原型如下:
void free (void* ptr);
free函數(shù)用來(lái)釋放動(dòng)態(tài)開(kāi)辟的內(nèi)存。
如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開(kāi)辟的,那free函數(shù)的行為是未定義的。
如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。
malloc和free都聲明在 stdlib.h 頭文件中。
舉個(gè)例子:
#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> int main() { //張三 //申請(qǐng) int* p = (int*)malloc(20); if (p == NULL) { printf("%s\n", strerror(errno)); return 1; } //使用 int i = 0; for (i = 0; i < 5; i++) { p[i] = i + 1; } for (i = 0; i < 5; i++) { printf("%d ", *(p + i)); } //釋放 free(p); p = NULL; return 0; }
代碼結(jié)果:
1,2,3,4,5
那我們?cè)囈辉囍苯哟蛴¢_(kāi)辟的動(dòng)態(tài)空間,看看里面的內(nèi)容是什么?
int main() { //張三 //申請(qǐng) int* p = (int*)malloc(20); if (p == NULL) { printf("%s\n", strerror(errno)); return 1; } //使用 int i = 0; for (i = 0; i < 5; i++) { printf("%d ", p[i]); } //釋放 free(p); p = NULL; return 0; }
代碼結(jié)果:
-842150451 -842150451 -842150451 -842150451 -842150451
發(fā)現(xiàn)malloc開(kāi)辟的動(dòng)態(tài)空間打印的是隨機(jī)值
C語(yǔ)言還提供了一個(gè)函數(shù)叫 calloc , calloc 函數(shù)也用來(lái)動(dòng)態(tài)內(nèi)存分配。原型如下:
void* calloc (size_t num, size_t size);
函數(shù)的功能是為 num 個(gè)大小為 size 的元素開(kāi)辟一塊空間,并且把空間的每個(gè)字節(jié)初始化為0。
與函數(shù) malloc 的區(qū)別只在于 calloc 會(huì)在返回地址之前把申請(qǐng)的空間的每個(gè)字節(jié)初始化為全0。
舉個(gè)例子:
int main() { int* p = (int*)calloc(10, sizeof(int)); if (p == NULL) { printf("calloc()-->%s\n", strerror(errno)); return 1; } //使用 int i = 0; for (i = 0; i < 10; i++) { printf("%d ", p[i]); } //釋放 free(p); p = NULL; return 0; }
代碼結(jié)果:
0 0 0 0 0 0 0 0 0 0
發(fā)現(xiàn)calloc開(kāi)辟的動(dòng)態(tài)空間打印的是0。
calloc和malloc的對(duì)比:
參數(shù)都是不一樣的
都是在堆區(qū)上申請(qǐng)的內(nèi)存空間,但是malloc不初始化,calloc會(huì)初始化為0
如果要初始化,就使用calloc
不需要初始化,就可以使用malloc
realloc函數(shù)的出現(xiàn)讓動(dòng)態(tài)內(nèi)存管理更加靈活。
有時(shí)會(huì)我們發(fā)現(xiàn)過(guò)去申請(qǐng)的空間太小了,有時(shí)候我們又會(huì)覺(jué)得申請(qǐng)的空間過(guò)大了,那為了合理的時(shí)候內(nèi)存,我們一定會(huì)對(duì)內(nèi)存的大小做靈活的調(diào)整。那 realloc 函數(shù)就可以做到對(duì)動(dòng)態(tài)開(kāi)辟內(nèi)存大小的調(diào)整。
函數(shù)原型如下:
void* realloc (void* ptr, size_t size);
ptr 是要調(diào)整的內(nèi)存地址
size 調(diào)整之后新大小
返回值為調(diào)整之后的內(nèi)存起始位置。
這個(gè)函數(shù)調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,還會(huì)將原來(lái)內(nèi)存中的數(shù)據(jù)移動(dòng)到 新 的空間。
realloc在調(diào)整內(nèi)存空間的是存在兩種情況:
情況1:原有空間之后有足夠大的空間
情況2:原有空間之后沒(méi)有足夠大的空間
情況1
當(dāng)是情況1 的時(shí)候,要擴(kuò)展內(nèi)存就直接原有內(nèi)存之后直接追加空間,原來(lái)空間的數(shù)據(jù)不發(fā)生變化。
情況2
當(dāng)是情況2 的時(shí)候,原有空間之后沒(méi)有足夠多的空間時(shí),擴(kuò)展的方法是:在堆空間上另找一個(gè)合適大小
的連續(xù)空間來(lái)使用。這樣函數(shù)返回的是一個(gè)新的內(nèi)存地址。
由于上述的兩種情況,realloc函數(shù)的使用就要注意一些。
舉個(gè)例子:
int main() { int* p = (int*)malloc(20); if (p == NULL) { printf("%s\n", strerror(errno)); return 1; } //使用 int i = 0; for (i = 0; i < 5; i++) { p[i] = i + 1; } int* ptr = (int*)realloc(p, 400000); if (ptr != NULL) { p = ptr; //使用 for (i = 5; i < 10; i++) { p[i] = i + 1; } for (i = 0; i < 10; i++) { printf("%d ", p[i]); } } //釋放 free(p); p = NULL; return 0; }
方案一:realloc函數(shù)返回的是舊地址
方案二:realloc函數(shù)返回的是新地址
realloc會(huì)找更大的空間
將原來(lái)的數(shù)據(jù)拷貝到新的空間
釋放舊的空間
返回新空間的地址
int main() { int* p = (int*)malloc(20); //可能會(huì)出現(xiàn)對(duì)NULL指針的解引用操作 //所以malloc函數(shù)的返回值要判斷的 int i = 0; for (i = 0; i < 5; i++) { p[i] = i; } free(p); p = NULL; return 0; }
int main() { int* p = (int*)malloc(20); if (p == NULL) { printf("%s\n", strerror(errno)); return 1; } //可能會(huì)出現(xiàn)對(duì)NULL指針的解引用操作 //所以malloc函數(shù)的返回值要判斷的 int i = 0; //越界訪(fǎng)問(wèn) for (i = 0; i < 10; i++) { p[i] = i; } free(p); p = NULL; return 0; }
//對(duì)非動(dòng)態(tài)開(kāi)辟內(nèi)存使用free釋放 int main() { int arr[10] = { 1,2,3,4,5 }; int* p = arr; //.... free(p); p = NULL; return 0; }
//使用free釋放一塊動(dòng)態(tài)開(kāi)辟內(nèi)存的一部分 int main() { int* p = (int*)malloc(40); if (p == NULL) { printf("%s\n", strerror(errno)); return 0; } int i = 0; //[1] [2] [3] [4] [5] [ ] [ ] [ ] [ ] [ ] for (i = 0; i < 5; i++) { *p = i + 1; p++; //這種寫(xiě)法不可取,如果想要釋放整個(gè)空間,必須將p放在起始位置上才可以 } //釋放 free(p); p = NULL; return 0; }
*p = i + 1;
p++; //這種寫(xiě)法不可取,如果想要釋放整個(gè)空間,必須將p放在起始位置上才可以,不然程序會(huì)崩潰掉
void test() { int* p = (int*)malloc(100); free(p); free(p);//重復(fù)釋放 }
//一直在吃?xún)?nèi)存,內(nèi)存不釋放 void test() { int* p = (int*)malloc(100); if (NULL != p) { *p = 20; } } int main() { test(); while (1); }
忘記釋放不再使用的動(dòng)態(tài)開(kāi)辟的空間會(huì)造成內(nèi)存泄漏。
切記:
動(dòng)態(tài)開(kāi)辟的空間一定要釋放,并且正確釋放 。
提示:
malloc,calloc,realloc,所申請(qǐng)的空間,如果不想使用,需要free釋放
如果不使用free釋放:程序結(jié)束之后,也會(huì)由操作系統(tǒng)回收!
如果不使用free釋放,程序也不結(jié)束,內(nèi)存就會(huì)泄露。
工作時(shí):
自己申請(qǐng)的,盡量自己釋放
自己不釋放的,告訴別人來(lái)釋放
這樣就可以避免動(dòng)態(tài)內(nèi)存泄漏的問(wèn)題
以上就是關(guān)于“C語(yǔ)言動(dòng)態(tài)內(nèi)存管理原理及實(shí)現(xiàn)的方法是什么”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。