成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

C語言動態(tài)內(nèi)存管理-創(chuàng)新互聯(lián)

C語言 動態(tài)內(nèi)存管理
  • 引言
    • C/C++程序的內(nèi)存開辟
    • 聲明
  • 一、動態(tài)內(nèi)存管理函數(shù)
    • 1. malloc 和 free
      • 使用示例
    • 2. calloc
      • 使用示例
    • 3. realloc
      • 使用示例
    • 4. 注意事項
  • 二、動態(tài)內(nèi)存管理函數(shù)使用時的錯誤示范
    • 程序清單1
    • 程序清單2
    • 程序清單3
    • 程序清單4
    • 程序清單5
    • 程序清單6
  • 三、經(jīng)典的內(nèi)存筆試題
    • 程序清單1
    • 程序清單2
    • 程序清單3
    • 程序清單4
    • 程序清單5

成都一家集口碑和實力的網(wǎng)站建設(shè)服務(wù)商,擁有專業(yè)的企業(yè)建站團(tuán)隊和靠譜的建站技術(shù),10余年企業(yè)及個人網(wǎng)站建設(shè)經(jīng)驗 ,為成都超過千家客戶提供網(wǎng)頁設(shè)計制作,網(wǎng)站開發(fā),企業(yè)網(wǎng)站制作建設(shè)等服務(wù),包括成都營銷型網(wǎng)站建設(shè),品牌網(wǎng)站制作,同時也為不同行業(yè)的客戶提供網(wǎng)站制作、成都網(wǎng)站制作的服務(wù),包括成都電商型網(wǎng)站制作建設(shè),裝修行業(yè)網(wǎng)站制作建設(shè),傳統(tǒng)機(jī)械行業(yè)網(wǎng)站建設(shè),傳統(tǒng)農(nóng)業(yè)行業(yè)網(wǎng)站制作建設(shè)。在成都做網(wǎng)站,選網(wǎng)站制作建設(shè)服務(wù)商就選創(chuàng)新互聯(lián)。引言 C/C++程序的內(nèi)存開辟

1-1

1. 棧區(qū):在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時這些存儲單元自動被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限,所以有時候會出現(xiàn)棧溢出的情況。 棧區(qū)主要存放運(yùn)行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回數(shù)據(jù)、返回地址等。

2. 堆區(qū):一般由程序員分配、釋放, 若程序員不釋放,程序結(jié)束時可能由操作系統(tǒng)回收,分配方式類似于鏈表。

3. 數(shù)據(jù)段 ( 靜態(tài)區(qū) static ) 存放全局變量、靜態(tài)數(shù)據(jù),程序結(jié)束后由系統(tǒng)釋放。

4. 代碼段:存放函數(shù)體(類成員函數(shù)和全局函數(shù))的二進(jìn)制代碼。

聲明

在我們平時寫程序時,創(chuàng)建的變量都會在底層開辟內(nèi)存。C語言 的內(nèi)存布局分為三大塊:棧區(qū)、堆區(qū)、靜態(tài)區(qū)。其中棧區(qū)是我們平時使用最多的區(qū)域,棧區(qū)的使用習(xí)慣:先使用高地址處的空間,再使用低地址處的空間。然而棧區(qū)的使用總是有限的,所以本篇博客重點介紹如何使用堆區(qū)的內(nèi)存。

1-2

一、動態(tài)內(nèi)存管理函數(shù) 1. malloc 和 free

malloc - memory allocate - 分配一段連續(xù)的內(nèi)存空間

void* malloc (size_t size);

// 返回值:申請內(nèi)存成功,則返回開辟好空間的頭指針;申請內(nèi)存失敗,則返回 NULL
// 參數(shù):以字節(jié)為單位的申請值

free - 釋放并回收內(nèi)存

void free (void* ptr);

// 參數(shù):ptr 為先前用 malloc、calloc 或 realloc分配的內(nèi)存塊的頭指針
// 注意:一定要是頭指針,而不是中間的指針,否則就會出現(xiàn)釋放內(nèi)存不干凈的情況
使用示例
#include#includeint main() {	int* p = (int*) malloc(40); // 申請空間

	if (p == NULL) {// 內(nèi)存分配失敗的情況
		perror("malloc");
		return 1;
	}

	for (int i = 0; i< 10; i++) {*(p + i) = i; 		// 為剛剛開辟的空間放入值
	}

	free(p);				// free 將剛剛系統(tǒng)開辟的空間,再回收掉
	p = NULL;				// 為了防止 ptr 成為野指針,所以將其置成 NULL
	return 0;
}
2. calloc

calloc - 分配一段連續(xù)的內(nèi)存空間并清零

calloc 函數(shù) 和 malloc 函數(shù)的使用思想基本相同,只不過前者在分配內(nèi)存之后,又做了清零的步驟。

void* calloc (size_t num, size_t size);

// 返回值:申請內(nèi)存成功,則返回開辟好空間的頭指針;申請內(nèi)存失敗,則返回 NULL
// 參數(shù):num 表示元素個數(shù),size 表示每個元素的字節(jié)大小
使用示例
#include#includeint main() {int* p = (int*) calloc(10, sizeof(int)); // 申請 10*4 = 40 個字節(jié)
	
	if (p == NULL) {perror("calloc");
		return 1;
	}

	for (int 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
3. realloc
void* realloc (void* ptr, size_t size);

使用 realloc 再次申請分配內(nèi)存的時候,需要指定重新開辟內(nèi)存的字節(jié)總大小。假設(shè)我們之前使用 malloc / calloc 申請內(nèi)存時,內(nèi)存不夠用了,realloc 就會派上用場。它可以做到很人性化地開辟內(nèi)存。

情況①:當(dāng) malloc / calloc 申請的內(nèi)存后面,有足夠的空間再次擴(kuò)充,realloc 就能夠直接接著上次的位置,繼續(xù)開辟。最終還是返回上一次開辟的原地址。

情況②:當(dāng) malloc / calloc 申請的內(nèi)存后面,沒有足夠的空間再次擴(kuò)充,realloc 也能夠另起一塊內(nèi)存區(qū)域,將之前申請的內(nèi)存中的數(shù)據(jù)也一并放入到新的內(nèi)存區(qū)域中。此時最終返回的是新的地址。

使用示例
#include#includeint main() {int* p = (int*) malloc(40);      // 1

	if (p == NULL) {perror("malloc");
		return 1;
	}

	for (int i = 0; i< 10; i++) {*(p + i) = i;
	}

	int* ptr = (int*)realloc(p, 80); // 2
	if (ptr != NULL) {		 // 3
		p = ptr;
	}
	
	free(p);						 // 4			
	p = NULL;			
	return 0;
}

// 1. malloc 申請分配內(nèi)存。

// 2. 假設(shè)空間不夠,使用 realloc 再次申請。

// 3. 由于內(nèi)存有限,所以 realloc 也有可能申請內(nèi)存失敗,當(dāng)失敗的時候就會返回 NULL. 只有當(dāng) ptr 不為空的時候,才能夠放入 p 中,這樣就能保證 p 不受影響。

// 4. 釋放內(nèi)存

4. 注意事項

申請內(nèi)存分配后,始終需要記得使用 free. 當(dāng)我們不釋放動態(tài)申請的內(nèi)存的時候,如果程序結(jié)束,動態(tài)申請的內(nèi)存由操作系統(tǒng)自動回收;但如果程序不結(jié)束,動態(tài)內(nèi)存是不會自動回收的,就會形成內(nèi)存泄露的問題,久而久之,內(nèi)存就會被 " 耗干 "。

雖然現(xiàn)在的操作系統(tǒng)很智能,能夠限制一些程序的內(nèi)存使用,但還是建議標(biāo)準(zhǔn)化。

二、動態(tài)內(nèi)存管理函數(shù)使用時的錯誤示范 程序清單1

動態(tài)內(nèi)存申請失敗,對 NULL 直接進(jìn)行了解引用操作。

#include#include#includeint main () {int* p = malloc(INT_MAX); // 申請失敗
	*p = 100; // error

	free(p);
	p = NULL;

	return 0;
}
程序清單2

對動態(tài)開辟空間的越界訪問。

#include#includeint main() {int* p = malloc(40); // 開辟 40 個字節(jié)的內(nèi)存
	if (p == NULL) {perror("malloc");
		return 1;
	}

	// 越界訪問 41 ~ 44
	for (int i = 0; i< 11; i++) {*(p + i) = i;
	}

	free(p);
	p = NULL;

	return 0;
}
程序清單3

對非動態(tài)開辟內(nèi)存使用 free 釋放.

#include#includeint main() {int a = 10;
	int* p = &a;

	free(p); // error
	p = NULL;

	return 0;
}
程序清單4

free 釋放不完整,或者 free 函數(shù)接收的指針不處于內(nèi)存開辟的頭部。

#include#includeint main() {int* p = (int*) malloc(100);
	if (p == NULL) {perror("malloc");
		return 1;
	}

	for (int i = 0; i< 10; i++) {*p = i;
		p++;
	}

	free(p); // error
	p = NULL;

	return 0;
}

從第 40 個字節(jié)后面開始釋放內(nèi)存,那么前面的內(nèi)存就未被釋放完。

1-3

程序清單5

對同一塊動態(tài)內(nèi)存多次釋放。

#include#includeint main() {int* p = malloc(100);

	if (p == NULL) {perror("malloc");
		return 1;
	}
	
	free(p);
	free(p); // error
	p = NULL;

	return 0;
}
程序清單6

內(nèi)存泄漏。

如下程序,在 test 函數(shù)中,即使我們寫了 free,但最終走不到釋放的代碼,依然會存在內(nèi)存泄漏的問題。所以說,free 代碼的放置位置很關(guān)鍵,并不是寫了 free 就一定能夠釋放動態(tài)內(nèi)存。

#include#includevoid test() {int* p = (int*)malloc(100);
	if (1) {return;
	}

	free(p); // 代碼走不到這一行
	p = NULL;
}

int main() {test();
	return 0;
}
三、經(jīng)典的內(nèi)存筆試題 程序清單1
#include#include#includevoid getMemory(char* p)
{p = (char*) malloc(100);
}

int main() {char* str = NULL;
	getMemory(str);
	strcpy(str, "hello world"); // 對空指針解引用

	printf(str);

	return 0;
}

分析:

在 getMemory 函數(shù)中,在堆區(qū)申請了 100 個字節(jié)的內(nèi)存大小,之后我們可以通過指針 p 來找到這些內(nèi)存。然而,在主函數(shù)中,str 始終為 NULL. 也就是說,str 并沒有指向任何一塊區(qū)域,所以后面在使用 strcpy 函數(shù)的時候," hello world " 就不能成功拷貝。

這題錯誤的主要原因就是 str 為實參,p 為形參,對形參的操作不影響實參。

1-4

程序清單2
#include#include#includevoid getMemory(char** p, int num)
{*p = (char*) malloc(num); // 相當(dāng)于 str 指向了開辟的 100 個字節(jié)的空間
	// *(&str)<==>str = (char*) malloc(100); 
}

int main() {char* str = NULL;
	getMemory(&str, 100);
	
	strcpy(str, "hello");
	printf(str);

	free(str); 			
	str = NULL; 		

	return 0;
}

// 輸出結(jié)果: hello

分析:

程序清單2 算是 對 程序清單1 的優(yōu)化,在 getMemory 函數(shù)中,當(dāng)我們傳過去的是 str 的地址時,再次對二級指針解引用,就相當(dāng)于能夠通過 str 直接找到開辟的內(nèi)存。上面的程序沒有問題,但是我們也不要忘記 free 來幫助系統(tǒng)回收內(nèi)存了。

1-5

程序清單3
#include#include#includechar* getMemory()
{char p[] = "hello world";
	return p;
}

int main() {char* str = NULL;
	str = getMemory();
	printf(str);

	return 0;
}

// 輸出結(jié)果:隨機(jī)值

分析:

數(shù)組 p 在棧區(qū)開辟了內(nèi)存,但出了 getMemory 函數(shù)后,數(shù)組中之前所占用的空間就被操作系統(tǒng)銷毀了,也就是說,剛剛棧區(qū)的內(nèi)存還給了系統(tǒng),現(xiàn)在出了函數(shù)后,即使知道這塊內(nèi)存的地址,但已經(jīng)沒有權(quán)限再次使用這塊區(qū)域了。因為數(shù)組 p 是一個臨時的局部變量。

p 表示數(shù)組的首元素地址,假設(shè) p 的地址為 0x11223344,那么出了 getMemory 函數(shù)后,現(xiàn)在 0x11223344 指向的內(nèi)存可能已經(jīng)被其他數(shù)據(jù)占用了。所以在主函數(shù)中,當(dāng) str 再次指向 0x11223344,找到的就是一些隨機(jī)存放的數(shù)據(jù)。

1-6

程序清單4
#includeint* test() {int a = 10;
	return &a;
	// 出了 test 函數(shù),a 的地址將被系統(tǒng)回收
}

int main() {int* p = test();

	return 0;
}

程序清單4 和 程序清單3 的錯誤思想基本相同,這是典型的 【返回棧空間地址、野指針】的問題。a 的地址出了 test 函數(shù)后,就需要被回收,所以后續(xù)在主函數(shù)中,指針 p 就沒有權(quán)限去操作這塊內(nèi)存區(qū)域。

為什么棧區(qū)的地址最后需要被回收?
答:因為函數(shù)和局部變量在使用時,需要在棧區(qū)開辟內(nèi)存,當(dāng)用完了,如果不被回收,那么操作系統(tǒng)的內(nèi)存遲早要被耗盡。

舉個例子:這就和住酒店一樣,當(dāng) 旅客 A 租完了房子,房子就需要打掃干凈,騰出來給后面的 旅客B / 旅客C / 旅客D… 使用。否則,房子永遠(yuǎn)不夠后面的旅客使用。如果 旅客A 前腳剛走,旅客B 就住進(jìn)去了,那么這個房子暫時屬于 旅客B 的,假設(shè) 旅客A 發(fā)現(xiàn)自己手機(jī)留在了剛剛的房子忘拿了,那么 旅客A 就需要和前臺報備一下,如果 旅客A 直接沖進(jìn)去了剛剛的房子找手機(jī),旅客B 就會告他非法訪問。

程序清單5
#includevoid test(){char* str = (char*) malloc(100);
	strcpy(str, "hello");
	free(str);
	
	if (str != NULL){		
		// 野指針,非法操作
		strcpy(str, "world");
		printf(str);
	}
}

int main() {test();
	return 0;
}

上面的代碼依舊是野指針問題,當(dāng) malloc 開辟的堆區(qū)內(nèi)存區(qū)域被 free 回收之后,str 指向的地址依舊是剛剛申請的頭部地址,但此時卻沒有了操作這塊內(nèi)存的權(quán)限。所以將 " world " 字符串放入 str 指向的區(qū)域,最終就會造成非法訪問。

綜上所述,我們應(yīng)該在 free 的后面添加如下代碼:

str = NULL; // 防止 str 成為一個野指針

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

本文標(biāo)題:C語言動態(tài)內(nèi)存管理-創(chuàng)新互聯(lián)
文章鏈接:http://jinyejixie.com/article0/dpogio.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、微信公眾號、面包屑導(dǎo)航ChatGPT、搜索引擎優(yōu)化軟件開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司
枣阳市| 晴隆县| 任丘市| 陇西县| 定兴县| 古田县| 武义县| 敖汉旗| 沐川县| 新田县| 龙海市| 沙雅县| 南木林县| 嘉义县| 洛川县| 咸丰县| 忻州市| 自治县| 铅山县| 大港区| 确山县| 喀什市| 七台河市| 大冶市| 余庆县| 油尖旺区| 保靖县| 南宁市| 麻栗坡县| 葫芦岛市| 鹤峰县| 柳州市| 济宁市| 马山县| 桑植县| 南阳市| 保德县| 金秀| 石泉县| 津市市| 封开县|