欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用c語言輕松實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存管

 更新時(shí)間:2023年01月18日 16:22:41   作者:小王學(xué)代碼  
這篇文章主要介紹了使用c語言輕松實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存管,本文章內(nèi)容詳細(xì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,需要的朋友可以參考下

前言

我們已經(jīng)掌握的內(nèi)存開辟的方法有兩種

int a = 10;      //在??臻g上開辟4個(gè)字節(jié)的空間

int a[10] = {0};  //在??臻g上開辟40個(gè)字節(jié)的連續(xù)空間

這些開辟方式都有兩個(gè)共同的特點(diǎn):

1.空間開辟大小是固定的

2.數(shù)組在申明的時(shí)候,必須指定數(shù)組的長度,它需要的內(nèi)存在編譯的時(shí)候分配

我們?yōu)槭裁匆獙?shí)現(xiàn)動(dòng)態(tài)管理內(nèi)存呢,這又什么作用呢?

我們對(duì)于空間的需求不僅僅只是上面兩種,有時(shí)候我們到底需要多少空間,需要運(yùn)行之后才能知道,這個(gè)時(shí)候就需要?jiǎng)討B(tài)開辟內(nèi)存空間,即動(dòng)態(tài)內(nèi)存函數(shù)就誕生了!

動(dòng)態(tài)內(nèi)存函數(shù)有那些?

1.malloc和free

2.calloc

3.realloc

malloc和free

malloc是C語言提供的一個(gè)動(dòng)態(tài)內(nèi)存開辟的函數(shù):

 這個(gè)函數(shù)向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針。

1.如果開辟成功,則返回一個(gè)指向開辟好空間的指針。

2.如果開辟失敗,則返回一個(gè) NULL 指針,因此 malloc 的返回值一定要做檢查。
3.返回值的類型是 void* ,所以 malloc 函數(shù)并不知道開辟空間的類型,具體在使用的時(shí)候使用者自己來決定。
4.如果參數(shù) size 為 0 , malloc 的行為是標(biāo)準(zhǔn)是未定義的,取決于編譯器。

void*的返回類型,使用的時(shí)候根據(jù)情況強(qiáng)制類型轉(zhuǎn)換

C語言還提供free函數(shù),專門是用于做動(dòng)態(tài)內(nèi)存的釋放和回收的,函數(shù)原型如下:

free函數(shù)是用來釋放動(dòng)態(tài)開辟的內(nèi)存:

1.如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開辟的,那free函數(shù)的行為是未定義的。(會(huì)報(bào)錯(cuò))

2.如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。

圖文演示:

頭文件要加上 malloc.h 

 代碼演示:

int main()
{
	int num = 0;
	scanf("%d", &num);
	//int arr[num] = { 0 };   num 在 [] 中
	//VS 不支持這樣,但是可以使用動(dòng)態(tài)內(nèi)存函數(shù),實(shí)現(xiàn)動(dòng)態(tài)數(shù)組
	int* ptr = (int*)malloc(sizeof(int) * num);
	if (NULL == ptr) {//進(jìn)行判斷是否創(chuàng)建成功
		perror("malloc::ptr");	
	}
	else {
		for (int i = 0; i < 10; i++) {
			*(ptr + i) = i;
		}
		for (int i = 0; i < 10; i++) {
			printf("%d ", *(ptr + i));
		}
		free(ptr);  //使用free函數(shù)釋放動(dòng)態(tài)申請(qǐng)的ptr
		ptr = NULL;  //將ptr  free之后,置為NULL,防止野指針非法訪問
	}
 
	return 0;
}

而且malloc函數(shù)創(chuàng)建的空間不會(huì)進(jìn)行初始化,里面存放的是隨機(jī)值,如圖

1.2 calloc

calloc函數(shù)也是C語言提供的,用來動(dòng)態(tài)內(nèi)存分配,原型如下:

calloc函數(shù)介紹:

1.函數(shù)的功能是為 num 個(gè)大小為 size 的元素開辟一塊空間,并且把空間的每個(gè)字節(jié)初始化為 0。
2.與函數(shù) malloc 的區(qū)別只在于 calloc 會(huì)在返回地址之前把申請(qǐng)的空間的每個(gè)字節(jié)初始化為全 0。

實(shí)操圖文分析:

 代碼演示:

int main()
{
	int num = 0;
	int* ptr = (int*)calloc(10, sizeof(int));//使用calloc函數(shù)
	for (int i = 0; i < 10; i++) {
			*(ptr + i) = i;
		}
		for (int i = 0; i < 10; i++) {
			printf("%d ", *(ptr + i));
		}
		free(ptr);//free 動(dòng)態(tài)申請(qǐng)的ptr
		ptr = NULL;//置為NULL,防止野指針越界訪問
	return 0;
 
}

對(duì)于calloc動(dòng)態(tài)申請(qǐng)的空間是否每一個(gè)字節(jié)都變?yōu)?呢?我們來看下圖

這也是calloc和malloc函數(shù)的最大的區(qū)別,是否自動(dòng)初始化,前者有,后者無

realloc

realloc也是C語言提供的動(dòng)態(tài)內(nèi)存申請(qǐng)函數(shù),使得動(dòng)態(tài)內(nèi)存管理更加靈活。

本質(zhì)是可以對(duì)已經(jīng)動(dòng)態(tài)申請(qǐng)過的空間進(jìn)行增容,是更加靈活的。

有時(shí)會(huì)我們發(fā)現(xiàn)過去申請(qǐng)的空間太小了,有時(shí)候我們又會(huì)覺得申請(qǐng)的空間過大了,那為了合理的時(shí) 候內(nèi)存,我們一定會(huì)對(duì)內(nèi)存的大小做靈活的調(diào)整。那 realloc 函數(shù)就可以做到對(duì)動(dòng)態(tài)開辟內(nèi)存大小 的調(diào)整。

 函數(shù)原型如下,并對(duì)兩個(gè)形參ptr和size進(jìn)行分析:

如上圖:

1.ptr可以為NULL,相當(dāng)于malloc一個(gè)新的空間,ptr是要調(diào)整的內(nèi)存地址

2.size同樣可以為0,則返回值取決于特定的庫實(shí)現(xiàn):它可能是空指針,也可能是不應(yīng)取消引用的其他位置。size是調(diào)整之后的大小

3.返回值為調(diào)整之后的內(nèi)存起始位置。

4.這個(gè)函數(shù)調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,還會(huì)將原來的數(shù)據(jù)移動(dòng)到新空間。

realloc調(diào)整內(nèi)存空間的時(shí)候有兩種情況:

第一種情況:當(dāng)原有空間之后的內(nèi)存空間足夠的時(shí)候

第二種情況:當(dāng)原有空間之后的內(nèi)存空間不夠時(shí)

如圖所示:

 因?yàn)檫@兩種情況是隨機(jī)發(fā)生的,不能控制必須使用哪一種,所以我們就要小心一個(gè)事情,不要用原來動(dòng)態(tài)開辟的變量ptr來直接接收realloc,應(yīng)該創(chuàng)建臨時(shí)變量接收,先判空,之后再賦值給ptr

代碼圖示:

 可以自行測試:

int main()
{
	int* p = (int*)malloc(sizeof(int)*10);
	if (p == NULL) {
		perror("malloc::p");
	}
	else {
		printf("%p\n", p);
	}
	int* ptr = (int*)realloc(p, sizeof(int) * 20);//創(chuàng)建臨時(shí)變量
//如果使用 int* p = (int*)realloc(p,....這樣的話如果創(chuàng)建失敗,返回NULL,
//這樣的話p的內(nèi)容就沒有了,所以創(chuàng)建臨時(shí)變量ptr,然后下面判空之后可以交換
	if (NULL == ptr) {
		perror("realloc::ptr");
	}
	else {
		p = ptr;
		ptr = NULL;
		printf("%p\n", p);
	}
 
	free(p);
	p = NULL;
	return 0;
}

常見動(dòng)態(tài)內(nèi)存錯(cuò)誤(案例分析)

對(duì)于NULL指針的解引用操作

意思就是要學(xué)會(huì)使用動(dòng)態(tài)內(nèi)存函數(shù)的時(shí)候嗎,要進(jìn)行判空,不然誰知道有沒有問題NULL

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	*p = 10;//這個(gè)時(shí)候誰知道p是不是NULL,如果是NULL,那么這就是非法訪問,是錯(cuò)誤
	free(p);
    return 0;
}

對(duì)動(dòng)態(tài)開辟空間的越界訪問

就是說,開辟多少空間就是多少空間,不能越過這個(gè)字節(jié)數(shù)的界限訪問空間外的地址

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	if (NULL == p) {
		perror("malloc::p");
	}
	else {
		for (int i = 0; i < 100; i++) {
			*(p + i) = i + 1;//當(dāng)i等于10的時(shí)候就開始越界訪問
		}
		for (int i = 0; i < 11; i++) {
			printf("%d ", *(p + i));
		}
		free(p);
		p = NULL;
	}
	return 0;
}

和數(shù)組一樣,不要越界,不需要多想什么額外的東西

對(duì)非動(dòng)態(tài)開辟內(nèi)存使用free釋放

free可以放置NULL進(jìn)去,不會(huì)報(bào)錯(cuò),但是不能放非動(dòng)態(tài)開辟的內(nèi)存,會(huì)報(bào)錯(cuò)

圖示分析free函數(shù):

 代碼演示:

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	int a = 10;
	free(&a);//非動(dòng)態(tài)內(nèi)存開辟的,會(huì)報(bào)錯(cuò)
//free(NULL);  //沒有什么反應(yīng),程序正常
	return 0;
}

使用free釋放了動(dòng)態(tài)開辟內(nèi)存的一部分

就是說如果動(dòng)態(tài)開辟內(nèi)存之后的p指針的位置發(fā)生改變的話再去釋放free(p)只是釋放一部分

代碼演示:

//舉例
int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	p++;
	free(p);//這個(gè)的時(shí)候p向右移動(dòng)一個(gè)整型字節(jié)空間,再進(jìn)行釋放,那么先前那個(gè)空間就沒被釋放
	return 0;
}

對(duì)同一塊動(dòng)態(tài)內(nèi)存進(jìn)行多次釋放

多次釋放會(huì)報(bào)錯(cuò)的

圖示:

動(dòng)態(tài)開辟空間忘記釋放(內(nèi)存泄漏)

所以我們要養(yǎng)成當(dāng)一個(gè)動(dòng)態(tài)空間不用的時(shí)候就free他,放置內(nèi)存泄露

代碼演示:

int main()
{
	//test();
	while (1) {
		malloc(1);//一直申請(qǐng)就是不釋放
	}
}

練習(xí)題

第一個(gè)

void GetMemory(char *p)
{
 p = (char *)malloc(100);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str);
//改為傳遞地址就可以或者就是用str接收
//str= GetMemory(str);//實(shí)際上用臨時(shí)變量接收更好
 strcpy(str, "hello world");
 printf(str);
//用完釋放
//free(str);
//str=NULL;
}

1.傳值操作,就算p申請(qǐng)了空間也不會(huì)使得str發(fā)生改變,所以str依舊是NULL,不能有strcpy

2.內(nèi)存泄漏, GetMemory(str);未釋放p的空間 

第二個(gè)

char *GetMemory(void)
{
//修改為:
//static char p[] = "hello world";
 char p[] = "hello world";
 return p;
}
void Test(void)
{
 char *str = NULL;
 str = GetMemory();
 printf(str);
}

典型的返回棧地址問題,p數(shù)組是局部變量 ,確實(shí)是返回了p的地址給str,但是GetMemory函數(shù)結(jié)束之后,數(shù)組p的空間就沒有,再訪問p的地址(printf(str))就會(huì)非法訪問

第三個(gè)

void GetMemory(char **p, int num)
{
 *p = (char *)malloc(num);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello");
 printf(str);
//修改為:free(str);
//str=NULL;
}

沒有釋放str動(dòng)態(tài)開辟的空間,沒有free(str),str=NULL

第四個(gè)

void GetMemory(char **p, int num)
{
 *p = (char *)malloc(num);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello");
 printf(str);
//修改為:free(str);
//str=NULL;
}

在使用str之前就釋放了str申請(qǐng)的空間,釋放之后str!=NULL,保留原來地址,str這個(gè)時(shí)候已經(jīng)是野指針了(因?yàn)闆]有了對(duì)相應(yīng)空間的訪問權(quán)限),之后確實(shí)是輸出了world,但是從if語句就已經(jīng)錯(cuò)誤了,置為str=NULL 就可以了

總結(jié)

本文主要是對(duì)于malloc、calloc、realloc、free函數(shù)的介紹和使用細(xì)節(jié)的說明,還有一些關(guān)于動(dòng)態(tài)內(nèi)存管理的函數(shù),學(xué)會(huì)了這些,對(duì)于以后數(shù)據(jù)結(jié)構(gòu)的內(nèi)容會(huì)更加得心應(yīng)手,所以希望大家能多多支持,接下來,下一章,我們跟大家講解一下,文件管理的內(nèi)容。學(xué)會(huì)了就可以更新通訊錄啦?。?!

以上就是使用c語言輕松實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存管的詳細(xì)內(nèi)容,更多關(guān)于c語言實(shí)現(xiàn)動(dòng)態(tài)內(nèi)存管的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論