亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C語言動態(tài)內(nèi)存管理的原理及實(shí)現(xiàn)方法

 更新時間:2023年04月19日 09:54:56   作者:熱愛跑步的恒川  
C語言動態(tài)內(nèi)存管理的原理是通過 malloc() 函數(shù)申請一塊連續(xù)的內(nèi)存空間,并返回其地址,通過 free() 函數(shù)釋放該內(nèi)存空間。實(shí)現(xiàn)方法是通過在程序運(yùn)行時動態(tài)地管理內(nèi)存,即在需要內(nèi)存時申請,不需要時釋放,避免了靜態(tài)內(nèi)存分配的浪費(fèi)和不足

1. 為什么存在動態(tài)內(nèi)存分配

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

int val = 20;//在棧空間上開辟四個字節(jié)
char arr[10] = {0};//在棧空間上開辟10個字節(jié)的連續(xù)空間

但是上述的開辟空間的方式有兩個特點(diǎn):

空間開辟大小是固定的。

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

但是對于空間的需求,不僅僅是上述的情況。有時候我們需要的空間大小在程序運(yùn)行的時候才能知道,

那數(shù)組的編譯時開辟空間的方式就不能滿足了。

這時候就只能試試動態(tài)存開辟了。

2. 動態(tài)內(nèi)存函數(shù)的介紹

2.1 malloc和free

C語言提供了一個動態(tài)內(nèi)存開辟的函數(shù):

void* malloc (size_t size);

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

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

C語言提供了另外一個函數(shù)free,專門是用來做動態(tài)內(nèi)存的釋放和回收的,函數(shù)原型如下:

void free (void* ptr);

free函數(shù)用來釋放動態(tài)開辟的內(nèi)存。

  • 如果參數(shù) ptr 指向的空間不是動態(tài)開辟的,那free函數(shù)的行為是未定義的。
  • 如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。

malloc和free都聲明在 stdlib.h 頭文件中。

舉個例子:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
int main()
{
	//張三
	//申請
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p[i] = i + 1;
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", *(p + i));
	}
	//釋放
	free(p);
	p = NULL;
	return 0;
}

代碼結(jié)果:

1,2,3,4,5

那我們試一試直接打印開辟的動態(tài)空間,看看里面的內(nèi)容是什么?

int main()
{
	//張三
	//申請
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", p[i]);
	}
	//釋放
	free(p);
	p = NULL;
	return 0;
}

代碼結(jié)果:

-842150451 -842150451 -842150451 -842150451 -842150451

發(fā)現(xiàn)malloc開辟的動態(tài)空間打印的是隨機(jī)值

2.2 calloc

C語言還提供了一個函數(shù)叫 calloc , calloc 函數(shù)也用來動態(tài)內(nèi)存分配。原型如下:

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

舉個例子:

int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		printf("calloc()-->%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (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

發(fā)現(xiàn)calloc開辟的動態(tài)空間打印的是0。

calloc和malloc的對比:

參數(shù)都是不一樣的

都是在堆區(qū)上申請的內(nèi)存空間,但是malloc不初始化,calloc會初始化為0

如果要初始化,就使用calloc

不需要初始化,就可以使用malloc

2.3 realloc

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

函數(shù)原型如下:

void* realloc (void* ptr, size_t size);
  • ptr 是要調(diào)整的內(nèi)存地址
  • size 調(diào)整之后新大小
  • 返回值為調(diào)整之后的內(nèi)存起始位置。
  • 這個函數(shù)調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,還會將原來內(nèi)存中的數(shù)據(jù)移動到 新 的空間。
  • realloc在調(diào)整內(nèi)存空間的是存在兩種情況:

情況1:原有空間之后有足夠大的空間

情況2:原有空間之后沒有足夠大的空間

情況1

當(dāng)是情況1 的時候,要擴(kuò)展內(nèi)存就直接原有內(nèi)存之后直接追加空間,原來空間的數(shù)據(jù)不發(fā)生變化。

情況2

當(dāng)是情況2 的時候,原有空間之后沒有足夠多的空間時,擴(kuò)展的方法是:在堆空間上另找一個合適大小

的連續(xù)空間來使用。這樣函數(shù)返回的是一個新的內(nèi)存地址。

由于上述的兩種情況,realloc函數(shù)的使用就要注意一些。

舉個例子:

int main()
{
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p[i] = i + 1;
	}
	int* ptr = (int*)realloc(p, 400000);
	if (ptr != NULL)
	{
		p = ptr;
		//使用
		for (i = 5; i < 10; i++)
		{
			p[i] = i + 1;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", p[i]);
		}
	}
	//釋放
	free(p);
	p = NULL;
	return 0;
}

方案一:realloc函數(shù)返回的是舊地址

方案二:realloc函數(shù)返回的是新地址

  • realloc會找更大的空間
  • 將原來的數(shù)據(jù)拷貝到新的空間
  • 釋放舊的空間
  • 返回新空間的地址

3. 常見的動態(tài)內(nèi)存錯誤

3.1 對NULL指針的解引用操作

int main()
{
	int* p = (int*)malloc(20);
	//可能會出現(xiàn)對NULL指針的解引用操作
	//所以malloc函數(shù)的返回值要判斷的
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p[i] = i;
	}
	free(p);
	p = NULL;
	return 0;
}

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

int main()
{
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//可能會出現(xiàn)對NULL指針的解引用操作
	//所以malloc函數(shù)的返回值要判斷的
	int i = 0;
	//越界訪問
	for (i = 0; i < 10; i++)
	{
		p[i] = i;
	}
	free(p);
	p = NULL;
	return 0;
}

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

//對非動態(tài)開辟內(nèi)存使用free釋放
int main()
{
	int arr[10] = { 1,2,3,4,5 };
	int* p = arr;
	//....
	free(p);
	p = NULL;
	return 0;
}

3.4 使用free釋放一塊動態(tài)開辟內(nèi)存的一部分

//使用free釋放一塊動態(tài)開辟內(nèi)存的一部分
int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	int i = 0;
	//[1] [2] [3] [4] [5] [ ] [ ] [ ] [ ] [ ] 
	for (i = 0; i < 5; i++)
	{
		*p = i + 1;
		p++;  //這種寫法不可取,如果想要釋放整個空間,必須將p放在起始位置上才可以
	}
	//釋放 
	free(p);
	p = NULL;
	return 0;
}

*p = i + 1;

p++; //這種寫法不可取,如果想要釋放整個空間,必須將p放在起始位置上才可以,不然程序會崩潰掉

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

void test()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);//重復(fù)釋放
}

3.6 動態(tài)開辟內(nèi)存忘記釋放(內(nèi)存泄漏)

//一直在吃內(nèi)存,內(nèi)存不釋放
void test()
{
	int* p = (int*)malloc(100);
	if (NULL != p)
	{
		*p = 20;
	}
}
int main()
{
	test();
	while (1);
}

忘記釋放不再使用的動態(tài)開辟的空間會造成內(nèi)存泄漏。

切記:

動態(tài)開辟的空間一定要釋放,并且正確釋放 。

提示:

malloc,calloc,realloc,所申請的空間,如果不想使用,需要free釋放

如果不使用free釋放:程序結(jié)束之后,也會由操作系統(tǒng)回收!

如果不使用free釋放,程序也不結(jié)束,內(nèi)存就會泄露。

工作時:

自己申請的,盡量自己釋放

自己不釋放的,告訴別人來釋放

這樣就可以避免動態(tài)內(nèi)存泄漏的問題

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

相關(guān)文章

  • c++實(shí)現(xiàn)二叉查找樹示例

    c++實(shí)現(xiàn)二叉查找樹示例

    這篇文章主要介紹了c++實(shí)現(xiàn)二叉查找樹示例,實(shí)現(xiàn)二叉查找樹的基本功能,需要的朋友可以參考下
    2014-02-02
  • C/C++?函數(shù)的存儲位置和占用空間詳解

    C/C++?函數(shù)的存儲位置和占用空間詳解

    Lambda函數(shù)的代碼部分在代碼段中,被捕獲的變量存儲在Lambda函數(shù)對象的內(nèi)部,這些變量的存儲位置取決于Lambda函數(shù)對象的存儲位置,這篇文章主要介紹了C/C++函數(shù)的存儲位置和占用空間,需要的朋友可以參考下
    2023-06-06
  • OpenCV?通過Mat遍歷圖像的方法匯總

    OpenCV?通過Mat遍歷圖像的方法匯總

    對圖像中的所有點(diǎn)或特殊點(diǎn)進(jìn)行運(yùn)算,所以遍歷圖像就顯得很重要,如何高效的遍歷圖像是一個很值得探討的問題,本文給大家?guī)砹硕喾N方法操作OpenCV?通過Mat遍歷圖像,感興趣的朋友一起看看吧
    2022-02-02
  • Matlab計(jì)算變異函數(shù)并繪制經(jīng)驗(yàn)半方差圖詳解

    Matlab計(jì)算變異函數(shù)并繪制經(jīng)驗(yàn)半方差圖詳解

    這篇文章主要為大家詳細(xì)介紹了基于MATLAB求取空間數(shù)據(jù)的變異函數(shù),并繪制經(jīng)驗(yàn)半方差圖的方法。文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2023-04-04
  • Qt實(shí)現(xiàn)簡單UDP通信

    Qt實(shí)現(xiàn)簡單UDP通信

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)簡單UDP通信,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • C語言實(shí)現(xiàn)二叉樹層次遍歷介紹

    C語言實(shí)現(xiàn)二叉樹層次遍歷介紹

    大家好,本篇文章主要講的是C語言實(shí)現(xiàn)二叉樹層次遍歷介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • C語言大小端字節(jié)序存儲模式深入解讀

    C語言大小端字節(jié)序存儲模式深入解讀

    我們知道,當(dāng)編譯器執(zhí)行 “創(chuàng)建變量” 這一代碼時,會在內(nèi)存中開辟空間相應(yīng)的空間來存儲變量值。而對于整型變量而言,變量值又是以二進(jìn)制補(bǔ)碼的形式存放的
    2022-09-09
  • C語言函數(shù)語法詳解

    C語言函數(shù)語法詳解

    本文是小結(jié)了一下C語言的函數(shù)語法,詳細(xì)介紹了C語言函數(shù)語法的概述、函數(shù)的定義、函數(shù)的返回值、函數(shù)調(diào)用等7個方面的內(nèi)容,非常詳細(xì),這里推薦給小伙伴們。
    2015-02-02
  • C語言中大小端問題實(shí)例探索解決方法

    C語言中大小端問題實(shí)例探索解決方法

    這篇文章主要介紹了C語言中大小端問題實(shí)例,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路
    2023-02-02
  • c++中template對字符串的處理方法

    c++中template對字符串的處理方法

    這篇文章主要介紹了c++中template對字符串的處理方法,需要的朋友可以參考下
    2014-07-07

最新評論