摘要:釋放不完全導(dǎo)致內(nèi)存泄漏。既然把柔性數(shù)組放在動(dòng)態(tài)內(nèi)存管理一章,可見(jiàn)二者有必然的聯(lián)系。包含柔性數(shù)組的結(jié)構(gòu)用進(jìn)行動(dòng)態(tài)內(nèi)存分配,且分配的內(nèi)存應(yīng)大于結(jié)構(gòu)大小,以滿(mǎn)足柔性數(shù)組的預(yù)期。使用含柔性數(shù)組的結(jié)構(gòu)體,需配合以等動(dòng)態(tài)內(nèi)存分配函數(shù)。
當(dāng)我們用類(lèi)型如int
,char
創(chuàng)建變量時(shí),所開(kāi)辟的空間都是固定的。而開(kāi)辟動(dòng)態(tài)內(nèi)存就是為了靈活的使用內(nèi)存,以滿(mǎn)足程序的需要。
在語(yǔ)言學(xué)習(xí)時(shí),對(duì)于內(nèi)存的劃分為上述三者:棧區(qū),堆區(qū),靜態(tài)區(qū)。棧區(qū)存放臨時(shí)變量,靜態(tài)區(qū)存放靜態(tài)變量,堆區(qū)用來(lái)動(dòng)態(tài)開(kāi)辟。
動(dòng)態(tài)內(nèi)存開(kāi)辟是在堆區(qū)上開(kāi)辟空間,具體如何開(kāi)辟請(qǐng)看下列函數(shù)。
malloc
& free
void* malloc( size_t size );
Return Valuemalloc returns a void pointer to the allocated space, or NULL if there is insufficient(不充足) memory available. To return a pointer to a type other than void, use a type cast(轉(zhuǎn)換) on the return value. Always check the return from malloc, even if the amount of memory requested is small.Parametersize - Bytes to allocate RemarksThe malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information.
void free( void* memblock );
Return ValueNoneParametermemblock - Previously allocated memory block to be freedRemarksThe free function deallocates(解除) a memory block that was previously allocated. If memblock is NULL, the pointer is ignored. Attempting to free a memblock isn"t allocated on heap may cause errors.
malloc
函數(shù)在堆區(qū)上申請(qǐng)size
個(gè)字節(jié)的空間,并返回該空間的起始地址。
free
函數(shù)釋放指針指向的動(dòng)態(tài)開(kāi)辟的空間,但不對(duì)指針造成任何影響。
malloc
返回通用類(lèi)型的指針,將其強(qiáng)制轉(zhuǎn)換為所需類(lèi)型,并用該類(lèi)型的指針維護(hù)該內(nèi)存空間。NULL
。free
釋放內(nèi)存以防內(nèi)存泄漏,將指針置空避免成為野指針。//申請(qǐng)空間int* p = (int*)malloc(40);//檢查if (p == NULL) { printf("%s/n", strerror(errno)); return -1;}//使用for (int i = 0; i < 10; i++) { *(p + i) = i; printf("%d ", *(p + i));}//釋放空間free(p);//置空p = NULL;
calloc
void* calloc( size_t num, size_t size );
Return Valuecalloc returns a pointer to the allocated space. To get a pointer to a type other than void, use a type cast on the return value. Parameters1. num - Number of elements2. size - Length in bytes of each elementRemarksThe calloc function allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0.
malloc
函數(shù)在堆區(qū)上申請(qǐng)num
個(gè)size
大小的空間,返回起始地址并將內(nèi)容初始化為0。
int* p = (int*)calloc(10, sizeof(int));if (p == NULL) { perror(""); return -1;}for (int i = 0; i < 10; i++) { *(p + i) = i; printf("%d ", p[i]);}free(p);p = NULL;
realloc
void* realloc( void* memblock, size_t size );
Return Valuerealloc returns a void pointer to the reallocated memory block. The return value is NULL if there is not enough available memory to expand the block to the given size, then the original block is unchanged.Parameters1. memblock - Pointer to previously allocated memory block2. size - New size in bytesRemarksThe realloc function changes the size of an allocated memory block. The memblock parament points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc. The contents of the block are unchanged, although the new block can be in a different location.
realloc
函數(shù)為已開(kāi)辟的空間重新開(kāi)辟大小。
NULL
。//1.p = (int*)realloc(p, 20 * sizeof(int));//2.int* ptr = (int*)realloc(p, 20 * sizeof(int));if (ptr == NULL) { return -1;}p = ptr;
防止增容失敗將原空間指針置空,故不可直接使用原指針接受返回值。判斷非空后再賦給原指針。
?
void test() { int* p = (int*)malloc(INT_MAX / 4); *p = 20; free(p);}
對(duì)指向動(dòng)態(tài)開(kāi)辟的空間的指針一定要做有效的判斷。
void test() { int i = 0; int* p = (int*)malloc(10 * sizeof(int)); if (NULL == p) { exit(EXIT_FAILURE); } for (int i = 0; i <= 10; i++) { *(p + i) = i; } free(p); p = NULL;}
作為程序員必須有意識(shí)地檢查所寫(xiě)的代碼是否有越界訪問(wèn)的問(wèn)題。
void test() { int a = 10; int* p = &a; free(p); p = NULL;}
不可用free
釋放非動(dòng)態(tài)開(kāi)辟的空間。
int main(){ int* p = (int*)malloc(100); p++; free(p); return 0;}
改變指向動(dòng)態(tài)開(kāi)辟內(nèi)存的指針,內(nèi)存將無(wú)法管理。釋放不完全導(dǎo)致內(nèi)存泄漏。
void test() { int* p = (int*)malloc(100); free(p); free(p);}
使用free
釋放已釋放的空間,即訪問(wèn)非法內(nèi)存。建議釋放內(nèi)存和指針置空搭配使用。
void test() { int *p = (int*)malloc(100); if(NULL != p) { *p = 20; }}int main() { test(); while(1);}
使用結(jié)束不釋放內(nèi)存造成內(nèi)存泄漏。程序不停止,系統(tǒng)也不會(huì)自動(dòng)回收。
?
調(diào)用下列
test
函數(shù),解釋運(yùn)行結(jié)果。
void GetMemory(char* p) { p = (char*)malloc(100);}void test() { char* str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); free(str); str = NULL;}
程序報(bào)錯(cuò)。
傳值調(diào)用:并沒(méi)有改變str
的值仍為不予修改的空指針,可以使用二級(jí)指針接收str
的地址。函數(shù)調(diào)用結(jié)束后指針?shù)N毀故無(wú)法釋放空間以致內(nèi)存泄漏。
char* GetMemory() { char p[] = "hello world"; return p;}void test() { char* str = NULL; str = GetMemory(); printf(str); free(str); str = NULL;}
程序打印隨機(jī)值。
返回??臻g地址:數(shù)組p
在函數(shù)內(nèi)創(chuàng)建,出函數(shù)銷(xiāo)毀,返回這部分空間的地址 ,屬于訪問(wèn)非法空間。
void GetMemory(char** p,int num) { *p = (char*)malloc(num);}void test() { char* str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); free(str); str = NULL;}
程序運(yùn)行成功,打印
"hello"
。
傳址調(diào)用:本題是例一的正確寫(xiě)法。
void test(void) { char* str = (char*)malloc(100); strcpy(str, "hello"); free(str); if (str != NULL) { strcpy(str, "world"); printf(str); }}
程序報(bào)錯(cuò)。
野指針:動(dòng)態(tài)開(kāi)辟的內(nèi)存釋放后指針不置空,造成野指針訪問(wèn)非法內(nèi)存。釋放內(nèi)存和指針置空應(yīng)該搭配起來(lái)使用。
釋放空間,銷(xiāo)毀空間都是將內(nèi)存空間歸還給操作系統(tǒng),即將此空間的使用權(quán)限歸還操作系統(tǒng)。雖不會(huì)改變空間內(nèi)容以致打印出所謂的“正確結(jié)果”,但可能在之后被操作系統(tǒng)分配給其他程序時(shí)發(fā)生修改。但無(wú)論改變與否,一旦空間歸還后再去訪問(wèn)就是訪問(wèn)非法內(nèi)存。
?
根據(jù)下列創(chuàng)建的各種變量,分析內(nèi)存的劃分。
int globalVar = 1;static int staticGlobalVar = 1;int main(){ static int staticVar = 1; int localVar = 1; int num1[10] = { 1,2,3,4 }; char char2[] = "abcd"; char* pChar3 = "abcd"; int* ptr1 = (int*)malloc(4 * sizeof(int)); int* ptr2 = (int*)calloc(4, sizeof(int)); int* ptr3 = (int*)realloc(ptr2, 4 * sizeof(int)); free(ptr1); free(ptr3); return 0;}
globalVal
,staticGobalVar
,staticVar
分別是全局變量和靜態(tài)變量,在數(shù)據(jù)段上創(chuàng)建。localVar
和num
,char2
,pchar
以及ptr
本身都是局部變量,都是在棧區(qū)上創(chuàng)建的。malloc
,calloc
,realloc
都是在堆區(qū)上開(kāi)辟的內(nèi)存塊,由指針ptr
指向而已。stack
):執(zhí)行函數(shù)時(shí),函數(shù)的局部變量都會(huì)在棧區(qū)上創(chuàng)建。壓棧:從棧頂向下開(kāi)辟空間,彈棧:從棧底向上釋放空間。heap
):一般由程序員分配和釋放,從堆低向上開(kāi)辟空間,堆頂向下釋放空間。在程序結(jié)束后也被操作系統(tǒng)會(huì)自動(dòng)回收。static
修飾后放在常量區(qū),程序結(jié)束后由系統(tǒng)釋放。語(yǔ)言學(xué)習(xí)時(shí)期,僅對(duì)內(nèi)存作此了解即可。內(nèi)核空間和內(nèi)存映射段會(huì)在操作系統(tǒng)中學(xué)習(xí),此處不再深入研究。
?
C99中引入柔性數(shù)組。柔性數(shù)組(flexible array)面試中雖不是重要的考點(diǎn),但仍需掌握最基本的使用。
在C99
中,結(jié)構(gòu)中最后一個(gè)元素允許是未知大小的數(shù)組,被稱(chēng)為柔性數(shù)組成員。例如:
//1.struct st_type { int i; int a[0];//柔性數(shù)組成員};//2.struct st_type { int i; int a[];//柔性數(shù)組成員};
語(yǔ)法規(guī)定數(shù)組大小中寫(xiě)0和不寫(xiě)都代表不指定大小。意味數(shù)組可大可小,這便是柔性的含義。
有些編譯器可能只支持一種寫(xiě)法。當(dāng)然柔性數(shù)組前必須有其他成員,類(lèi)型一致是為了避免考慮內(nèi)存對(duì)齊。既然把柔性數(shù)組放在動(dòng)態(tài)內(nèi)存管理一章,可見(jiàn)二者有必然的聯(lián)系。
結(jié)構(gòu)中柔性數(shù)組成員前必須至少有一個(gè)成員。
sizeof
計(jì)算結(jié)構(gòu)所占空間時(shí)不包含柔性數(shù)組的大小。
包含柔性數(shù)組的結(jié)構(gòu)用malloc
進(jìn)行動(dòng)態(tài)內(nèi)存分配,且分配的內(nèi)存應(yīng)大于結(jié)構(gòu)大小,以滿(mǎn)足柔性數(shù)組的預(yù)期。
使用含柔性數(shù)組的結(jié)構(gòu)體,需配合以
malloc
等動(dòng)態(tài)內(nèi)存分配函數(shù)。分配空間減去其他成員的大小,即為為柔性數(shù)組開(kāi)辟的空間。
malloc
開(kāi)辟的大小寫(xiě)成如圖所示的形式,增加代碼的可閱讀性。結(jié)構(gòu)體所分配空間減去其他成員的大小,所剩即為為柔性數(shù)組開(kāi)辟的空間大小,若不夠還可以用
realloc
調(diào)整大小,以滿(mǎn)足柔性數(shù)組“柔性”的需求。
struct st_type { int i; int a[0];};int main() { printf("%d/n", sizeof(struct st_type)); //1. struct st_type st; //2. struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int)); if (pst == NULL) { perror("pst"); return -1; } return 0;}
含柔性數(shù)組結(jié)構(gòu)體當(dāng)然不可像第一種那樣使用,這樣結(jié)構(gòu)體變量st
僅有4個(gè)字節(jié),不包含柔性數(shù)組。
struct st_type { int i; int a[0];};int main() { struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int)); if (pst == NULL) { perror("pst"); return -1; } pst->i = 10; for (int i = 0; i < 10; i++) { printf("%d ", pst->a[i] = i); } //調(diào)整空間大小 struct st_type* ptr = (struct st_type*)realloc(pst, sizeof(struct st_type) + 20 * sizeof(int)); if (ptr == NULL) { perror("ptr"); return -1; } pst = ptr; for (int i = 10; i < 20; i++) { printf("%d ", pst->a[i] = i); } //釋放 free(pst); pst = NULL; return 0;}
柔性數(shù)組成員利用動(dòng)態(tài)內(nèi)存可大可小,那同樣將柔性數(shù)組成員替換成指向動(dòng)態(tài)開(kāi)辟內(nèi)存的指針也可達(dá)到同樣的效果。下文將對(duì)比二者都有何優(yōu)劣。(為突出對(duì)比,已省略不必要的代碼)
struct st_type { int i; int a[];};int main() { struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type) + 10 * sizeof(int)); for (int i = 0; i < 10; i++) { printf("%d ", pst->a[i] = i); } //調(diào)整空間大小 struct st_type* ptr = (struct st_type*)realloc(pst, sizeof(struct st_type) + 20 * sizeof(int)); pst = ptr; for (int i = 10; i < 20; i++) { printf("%d ", pst->a[i] = i); } //釋放 free(pst); pst = NULL; return 0;}
struct st_type { int i; int* pa;};int main() { struct st_type* pst = (struct st_type*)malloc(sizeof(struct st_type)); pst->pa = (int*)malloc(10 * sizeof(int)); for (int i = 0; i < 10;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/121538.html
摘要:棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。棧區(qū)主要存放運(yùn)行函數(shù)而分配的局部變量函數(shù)參數(shù)返回?cái)?shù)據(jù)返回地址等。 C語(yǔ)言動(dòng)態(tài)內(nèi)存分配篇 目錄 一、為什么存在動(dòng)態(tài)內(nèi)存管理/分配? ????????內(nèi)存的存儲(chǔ)形式劃分 二、動(dòng)態(tài)內(nèi)存函數(shù)的介紹 ????????malloc ...
摘要:在運(yùn)行腳本時(shí),需要顯示的指定對(duì)象。大對(duì)象區(qū)每一個(gè)區(qū)域都是由一組內(nèi)存頁(yè)構(gòu)成的。這里是唯一擁有執(zhí)行權(quán)限的內(nèi)存區(qū)。換句話說(shuō),是該對(duì)象被之后所能回收到內(nèi)存的總和。一旦活躍對(duì)象已被移出,則在舊的半空間中剩下的任何死亡對(duì)象被丟棄。 內(nèi)存管理 本文以V8為背景 對(duì)之前的文章進(jìn)行重新編輯,內(nèi)容做了很多的調(diào)整,使其具有邏輯更加緊湊,內(nèi)容更加全面。 1. 基礎(chǔ)概念 1.1 生命周期 不管什么程序語(yǔ)言,內(nèi)存...
摘要:之前的通訊錄在程序退出后內(nèi)部的數(shù)據(jù)就會(huì)消失,再次打開(kāi)程序后只能重新輸入數(shù)據(jù),為此我們?cè)黾恿艘粋€(gè)保存功能來(lái)保存信息。 前言: 由于之前實(shí)現(xiàn)的通訊錄在存儲(chǔ)方面只能支持靜態(tài)的1000人的存儲(chǔ)量,但是如果聯(lián)系人較少,則會(huì)造成較大的內(nèi)存浪費(fèi)。而當(dāng)聯(lián)系人一旦超過(guò)1000時(shí),就不能再繼續(xù)存儲(chǔ)信息了。因...
摘要:種一顆樹(shù)最好的時(shí)機(jī)是十年前,其次是現(xiàn)在經(jīng)過(guò)一段刻骨的升本歷程,來(lái)到了西華大學(xué)。計(jì)劃是前進(jìn)的路線圖免除對(duì)于以后學(xué)習(xí)的各自夸大的計(jì)劃,從實(shí)際出發(fā)找到適合自己的前進(jìn)的路線圖。今年我歲,年輕。 種一顆樹(shù)最好的時(shí)機(jī)是十年前,其次是現(xiàn)在 經(jīng)過(guò)一段刻骨的升本歷程,來(lái)到了西華大學(xué)。明顯能感覺(jué)到自己又有了新的...
閱讀 994·2021-11-24 10:42
閱讀 3539·2021-11-19 11:34
閱讀 2681·2021-09-29 09:35
閱讀 2574·2021-09-09 09:33
閱讀 708·2021-07-26 23:38
閱讀 2554·2019-08-30 10:48
閱讀 1419·2019-08-28 18:07
閱讀 454·2019-08-26 13:44