成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

C語(yǔ)言進(jìn)階:動(dòng)態(tài)內(nèi)存管理

shinezejian / 2680人閱讀

摘要:釋放不完全導(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)態(tài)內(nèi)存管理

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

當(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ù)。

動(dòng)態(tài)內(nèi)存函數(shù)的介紹

開(kāi)辟釋放函數(shù) malloc & free
函數(shù)聲明
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ì)指針造成任何影響。

函數(shù)用法
  • malloc返回通用類(lèi)型的指針,將其強(qiáng)制轉(zhuǎn)換為所需類(lèi)型,并用該類(lèi)型的指針維護(hù)該內(nèi)存空間。
  • 開(kāi)辟成功返回空間起始地址,開(kāi)辟失敗則返回NULL。
  • 使用結(jié)束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;
內(nèi)存開(kāi)辟函數(shù) calloc
函數(shù)聲明
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。

函數(shù)用法
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;
內(nèi)存調(diào)整函數(shù) realloc
函數(shù)聲明
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)辟大小。

函數(shù)用法
  • 當(dāng)原空間后有足夠大小時(shí),就緊接原空間開(kāi)辟剩余空間,并返回整個(gè)空間的起始地址。

  • 當(dāng)原空間后無(wú)足夠大小時(shí),就在堆區(qū)尋找新空間,再將原空間的內(nèi)容移動(dòng)到新空間,返回新空間的地址且釋放原空間。

  • 當(dāng)剩余空間不夠無(wú)法開(kāi)辟時(shí),增容失敗,返回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;

防止增容失敗將原空間指針置空,故不可直接使用原指針接受返回值。判斷非空后再賦給原指針。

?

常見(jiàn)的動(dòng)態(tài)內(nèi)存錯(cuò)誤

1.不檢查空指針
void test() {	int* p = (int*)malloc(INT_MAX / 4);	*p = 20;	free(p);}

對(duì)指向動(dòng)態(tài)開(kāi)辟的空間的指針一定要做有效的判斷。

2.越界訪問(wèn)
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)題。

3.釋放非動(dòng)態(tài)開(kāi)辟內(nèi)存
void test() {	int a = 10;	int* p = &a;	free(p);    p = NULL;}

不可用free釋放非動(dòng)態(tài)開(kāi)辟的空間。

4.釋放部分內(nè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)存泄漏。

5.重復(fù)釋放內(nèi)存
void test() {	int* p = (int*)malloc(100);	free(p);	free(p);}

使用free釋放已釋放的空間,即訪問(wèn)非法內(nèi)存。建議釋放內(nèi)存和指針置空搭配使用。

6.忘記釋放內(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é)果。

Example 1
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)存泄漏。

Example 2
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)非法空間。

Example 3
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ě)法。

Example 4
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)存。

?

C/C++內(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;}
  1. globalVal,staticGobalVar,staticVar分別是全局變量和靜態(tài)變量,在數(shù)據(jù)段上創(chuàng)建。
  2. localVarnum,char2,pchar以及ptr本身都是局部變量,都是在棧區(qū)上創(chuàng)建的。
  3. malloc,calloc,realloc都是在堆區(qū)上開(kāi)辟的內(nèi)存塊,由指針ptr指向而已。
內(nèi)存劃分圖示

  1. 棧區(qū)(stack):執(zhí)行函數(shù)時(shí),函數(shù)的局部變量都會(huì)在棧區(qū)上創(chuàng)建。壓棧:從棧頂向下開(kāi)辟空間,彈棧:從棧底向上釋放空間。
  2. 堆區(qū)(heap):一般由程序員分配和釋放,從堆低向上開(kāi)辟空間,堆頂向下釋放空間。在程序結(jié)束后也被操作系統(tǒng)會(huì)自動(dòng)回收。
  3. 數(shù)據(jù)段(靜態(tài)區(qū)):存放全局變量,靜態(tài)數(shù)據(jù)。變量本在棧上創(chuàng)建,被static修飾后放在常量區(qū),程序結(jié)束后由系統(tǒng)釋放。
  4. 代碼段(常量區(qū)):存放可執(zhí)行代碼和只讀常量。

語(yǔ)言學(xué)習(xí)時(shí)期,僅對(duì)內(nèi)存作此了解即可。內(nèi)核空間和內(nèi)存映射段會(huì)在操作系統(tǒng)中學(xué)習(xí),此處不再深入研究。

?

柔性數(shù)組

C99中引入柔性數(shù)組。柔性數(shù)組(flexible array)面試中雖不是重要的考點(diǎn),但仍需掌握最基本的使用。

柔性數(shù)組的定義

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)系。

柔性數(shù)組的特點(diǎ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)辟的空間。

柔性數(shù)組的使用

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ù)組。

Example
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ù)組的優(yōu)勢(shì)

柔性數(shù)組成員利用動(dòng)態(tài)內(nèi)存可大可小,那同樣將柔性數(shù)組成員替換成指向動(dòng)態(tài)開(kāi)辟內(nèi)存的指針也可達(dá)到同樣的效果。下文將對(duì)比二者都有何優(yōu)劣。(為突出對(duì)比,已省略不必要的代碼)

柔性數(shù)組版本
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

相關(guān)文章

  • C語(yǔ)言進(jìn)階動(dòng)態(tài)內(nèi)存管理/分配

    摘要:棧內(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 ...

    Carson 評(píng)論0 收藏0
  • 【前端進(jìn)階之路】內(nèi)存基本知識(shí)

    摘要:在運(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)存...

    Simon_Zhou 評(píng)論0 收藏0
  • C語(yǔ)言進(jìn)階C語(yǔ)言實(shí)現(xiàn)通訊錄 升級(jí)版 { 含動(dòng)態(tài)擴(kuò)容/銷(xiāo)毀/信息保存功能 }(強(qiáng)烈建議收藏食用)

    摘要:之前的通訊錄在程序退出后內(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ǔ)信息了。因...

    gxyz 評(píng)論0 收藏0
  • 是,入坑小記

    摘要:種一顆樹(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é)到自己又有了新的...

    CoXie 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<