最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言實(shí)現(xiàn)動態(tài)內(nèi)存分配

 更新時間:2026年07月05日 08:37:15   作者:雨白  
本文主要介紹了C語言實(shí)現(xiàn)動態(tài)內(nèi)存分配,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

棧區(qū)與堆區(qū)初探

C程序會對內(nèi)存進(jìn)行分區(qū),主要分為5個區(qū)域:

  • 棧區(qū)(Stack)
  • 堆區(qū)(Heap)
  • 全局/靜態(tài)區(qū)
  • 常量區(qū)(Constant)
  • 代碼區(qū)

我們先主要了解前兩個:

棧內(nèi)存由編譯器自動分配和釋放,我們不需要操心。每調(diào)用一個函數(shù),都會在棧區(qū)為該函數(shù)分配一塊內(nèi)存區(qū)域,這塊區(qū)域就叫做函數(shù)棧幀。其中主要存放一些非靜態(tài)的局部變量、函數(shù)參數(shù)等。

例如,下面代碼中的函數(shù)形參 b、定義的局部變量 a 所用到的內(nèi)存,都會由編譯器自動開辟,開辟的方式是靜態(tài)內(nèi)存開辟。當(dāng) add 函數(shù)執(zhí)行完畢返回時,對應(yīng)的函數(shù)棧幀就會被銷毀,自然這些占用的內(nèi)存會被編譯器自動回收。

int add(int b) {
	int a = 10;
	return a + b;
}

堆內(nèi)存由我們程序員手動分配(malloccalloc)和釋放(free)。

malloc 和 calloc 的區(qū)別在于:malloc 分配的內(nèi)存存儲的都是未初始化的隨機(jī)垃圾值,而 calloc 會自動將分配的內(nèi)存全部初始化為 0。

#include <stdio.h>
#include <stdlib.h>

int main() {
	// 申請了32MB的內(nèi)存
	int* arr = (int*) malloc(8 * 1024 * 1024 * sizeof(int)); // 返回值類型是void*,表示無類型指針,我們可以強(qiáng)轉(zhuǎn)賦予它類型
	
	// 每次動態(tài)分配內(nèi)存后,都要檢查返回值是否為 NULL
	if (arr == NULL) {
		// 防止操作到空指針,導(dǎo)致程序崩潰
		printf("Memory allocation failed!\n");
		return -1; 
	}

	// 釋放內(nèi)存        
	free(arr);
	// 置空,防止野指針
	arr = NULL;
	
	return 0;
}

堆內(nèi)存的開辟方式是動態(tài)內(nèi)存開辟,這些內(nèi)存不會自動回收,如果不手動回收,就會造成內(nèi)存泄漏。

此外,??臻g通常很?。?MB),堆空間則很大,和系統(tǒng)可用的內(nèi)存有關(guān)。

運(yùn)行時決定內(nèi)存大小

動態(tài)內(nèi)存開辟的使用場景有很多:數(shù)據(jù)長度只在運(yùn)行時才確定、??臻g不滿足需求、需要延長變量的生命周期、內(nèi)存大小需要動態(tài)改變等。

我們以第一種場景為例:運(yùn)行時由用戶輸入決定人員的數(shù)量。

#include <stdio.h>
#include <stdlib.h>

int main() {
	// 用戶輸入
	int num = 0;
	printf("Please enter the number of people.\n");
	scanf_s("%d", &num);

	// 開辟對應(yīng)大小的空間
	int* arr = (int*)malloc(num * sizeof(int));
	
	// 檢查內(nèi)存是否開辟成功
	if (arr == NULL) {
		printf("Memory allocation failed!\n");
		return -1; // 退出程序
	}

	for (int i = 0; i < num; i++)
	{
		// 輸入年齡
		int age = 0;
		printf("Please enter the age of the %d member at this position.\n", i + 1);
		scanf_s("%d", &age);
		arr[i] = age;
	}

	// 輸出每個人的年齡
	for (int i = 0; i < num; i++)
	{
		printf("The age of the %d member is %d\n", i + 1, arr[i]);
	}

	// 釋放并置空
	free(arr);
	arr = NULL;
	
	return 0;
}

scanf_s 是 Visual Studio 環(huán)境下特有的安全函數(shù),在非 VS 環(huán)境中請使用 scanf。

運(yùn)行結(jié)果:

realloc 的擴(kuò)容機(jī)制與暗坑

再來看看第四種場景,普通的數(shù)組一旦定義后,長度就固定了,而動態(tài)內(nèi)存的大小可以使用 realloc 進(jìn)行重新調(diào)整,根據(jù)自己的需要擴(kuò)容或縮容。

使用 realloc 進(jìn)行擴(kuò)容時,有兩種情況:

原地擴(kuò)容:如果原位置后有足夠的連續(xù)內(nèi)存空間,它會直接在原地址后追加空間,返回的地址和原地址相同。

異地擴(kuò)容:如果原位置所需的連續(xù)地址空間不足,它會嘗試在堆區(qū)找到一塊合適的內(nèi)存空間,將之前的數(shù)據(jù)拷貝到新位置,并自動釋放之前的舊內(nèi)存,最后返回指向這塊新內(nèi)存空間的指針。

因?yàn)楫惖財U(kuò)容很常見,所以我們應(yīng)該總是要使用新的指針去接收返回值。同時,如果發(fā)生后了異地擴(kuò)容,原來的指針就變?yōu)榱艘爸羔槪瑧?yīng)該置為空。

#include <stdio.h>
#include <stdlib.h>

int main() {
	// 初始可以存儲8個整型
	int* p = (int*)malloc(8 * sizeof(int));
	if (p == NULL) {
		printf("Initial memory allocation failed.\n");
		return -1;
	}

	for (int i = 0; i < 8; i++)
	{
		p[i] = i + 1;
	}

	printf("Before capacity expansion\n");
	for (int i = 0; i < 8; i++)
	{
		printf("%d ", p[i]);
	}

	// 擴(kuò)容至16
	printf("\nAfter capacity expansion\n");
	
	// 使用新指針變量接收,防止因擴(kuò)容失敗導(dǎo)致原內(nèi)存地址 p 丟失
	int* new_p = (int*)realloc(p, 16 * sizeof(int));
	
	if (new_p == NULL) {
		printf("\nFailed to allocate memory for expansion.\n");
		// 擴(kuò)容失敗,舊內(nèi)存 p 依然有效,程序結(jié)束前記得釋放
		free(p);
		p = NULL;
		return -1;
	}

	// 擴(kuò)容成功,原指針 p 可能已在異地擴(kuò)容中被自動釋放而失效,為防止誤用,我們將其置空
	p = NULL; 

	for (int i = 8; i < 16; i++)
	{
		new_p[i] = i + 1;
	}
	for (int i = 0; i < 16; i++)
	{
		printf("%d ", new_p[i]);
	}

	// 此時由 new_p 管理這塊空間,我們只需釋放 new_p
	free(new_p);
	new_p = NULL;

	return 0;
}

如果 realloc 擴(kuò)容失敗,它將返回 NULL 空指針,但舊內(nèi)存不會被釋放,我們需要手動處理。

#include <stdio.h>
#include <stdlib.h>

int main() {
	int* p = (int*)malloc(8 * sizeof(int));
	if (p == NULL) return -1;
	
	// 嘗試申請一塊非常大的內(nèi)存,模擬失敗的情況
	int* new_p = (int*)realloc(p, 8 * 1024LL * 1024 * 1024 * sizeof(int));

	if (new_p == NULL)
	{
		printf("Failed to allocate memory.\n");
		// 雖然申請新內(nèi)存失敗,但是舊內(nèi)存塊 p 依然存在,需要由我們手動釋放
		free(p);
		p = NULL;
	}
	else 
	{
		printf("Success to allocate memory.\n");
		// 如果成功,釋放新指針 new_p 即可
		free(new_p);
		new_p = NULL;
		p = NULL; // 置空防誤用
	} 
	
	return 0;
}

注意:永遠(yuǎn)不要多次釋放同一塊內(nèi)存,可能會導(dǎo)致程序崩潰。

到此這篇關(guān)于C語言實(shí)現(xiàn)動態(tài)內(nèi)存分配的文章就介紹到這了,更多相關(guān)C語言 動態(tài)內(nèi)存分配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

北碚区| 天镇县| 宜州市| 会东县| 财经| 屯昌县| 博客| 临城县| 慈溪市| 宁晋县| 阿瓦提县| 咸宁市| 水城县| 平武县| 黄冈市| 新密市| 德化县| 富源县| 大田县| 万山特区| 景德镇市| 黔东| 台南市| 甘肃省| 南康市| 揭西县| 鄄城县| 合川市| 聂荣县| 大化| 图们市| 凯里市| 遵义市| 安庆市| 惠州市| 繁峙县| 仪征市| 漳浦县| 铜山县| 吉林市| 固安县|