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

C語言中動態(tài)內存管理圖文詳解

 更新時間:2022年06月17日 16:24:16   作者:烤雞肉玉米煎餅  
在編寫程序時,通常并不知道需要處理的數(shù)據(jù)量,或者難以評估所需處理數(shù)據(jù)量的變動程度,下面這篇文章主要給大家介紹了關于C語言中動態(tài)內存管理的相關資料,需要的朋友可以參考下

1.動態(tài)內存開辟的原因

常見的內存開辟方式

int val = 20;//在??臻g上開辟四個字節(jié)的空間

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

上面開辟空間的方式有兩個特點:

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

2. 數(shù)組在聲明的時候,必須指定數(shù)組的長度,它所需要的空間在編譯時分配;

但是對于空間的需求,不只是上面的情況,有時候需要的空間大小在程序運行的時候才能得知,這時候數(shù)組的編譯時開辟空間的方式就不能滿足了。

所以需要動態(tài)開辟內存

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

動態(tài)內存的開辟都是在內存的堆區(qū)中進行開辟的

2.1malloc和free

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

void* malloc(size_t size);

malloc函數(shù)向內存申請一塊連續(xù)可用的空間,并返回指向這塊空間起始位置的指針。

1.如果開辟成功,則返回一個指向開辟好的空間的指針;

2.如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查,不然可能會造成野指針的問題;

3.返回值的類型時void*,所以malloc函數(shù)并不知道開辟空間的類型,具體在使用的時候由使用者自己來決定返回值的類型;

4.如果參數(shù)size為0,此時malloc函數(shù)的行為是標準未定義的,取決于程序運行時使用的編譯器;

malloc的使用:

vint main()
{
	int* p = (int*)malloc(40);//向內存申請一塊40字節(jié)的空間,并對放回的指針類型轉換
	if (p == NULL)//返回NULL指針時讓打印錯誤信息并讓程序結束
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	return 0;
}

要記得包含頭文件<stdlib.h>

這樣就對開辟的內存空間進行了一個使用了,但是還有點問題,因為向內存申請的空間沒有進行釋放。

所以這時就引入了另一個函數(shù)free

C語言提供了另一個函數(shù)free,專門用來做動態(tài)內存的釋放和回收的

void free(void* ptr);

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

1.如果參數(shù)ptr指向的空間是不是動態(tài)開辟的,那么free函數(shù)的行為是未定義的;

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

malloc和free函數(shù)都聲明在stdlib.h頭文件中

free的使用:

int main()
{
	int* p = (int*)malloc(40);//向內存申請一塊40字節(jié)的空間,并對放回的指針類型轉換
	if (p == NULL)//返回NULL指針時讓打印錯誤信息并讓程序結束
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	free(p);//釋放p所指向的動態(tài)內存
	p == NULL;//將p的值置為NULL
	return 0;
}

free的參數(shù)一定是動態(tài)開辟內存空間的那個起始位置的地址,否則會報錯

在用free釋放完動態(tài)開辟的內存之后,要對之前指向動態(tài)開辟空間的那個指針置為NULL,因為那塊動態(tài)開辟的空間已經(jīng)被操作系統(tǒng)回收了,沒有了訪問的權限,所以要讓p的值為NULL,避免野指針的問題。

如果對動態(tài)內存開辟的空間沒有釋放掉,會出現(xiàn)一個內存泄漏的問題。

2.2calloc

C語言還提供了一個calloc函數(shù),calloc也是用來進行動態(tài)內存的分配

void* calloc(size_t num, size_t size);

 1.calloc的功能是為num個字節(jié)大小為size的元素開辟一個空間,并且把空間的每個字節(jié)的數(shù)據(jù)都初始化為0,然后返回這塊連續(xù)空間的起始位置的地址;

2.與malloc函數(shù)的區(qū)別只在于,calloc在返回地址之前會把申請的空間的每個字節(jié)的數(shù)據(jù)都初始化為全0;

calloc的使用:

int main()
{
	int* p = (int*)calloc(10, 4);
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	free(p);
	p = NULL;
	return 0;
}

內存情況:

 可以看到,動態(tài)開辟的40個字節(jié)的空間都被初始化為全0

所以如果要對動態(tài)開辟的空間進行初始化,可以直接使用calloc函數(shù)來完成

2.3realloc

有時會發(fā)現(xiàn)申請的空間太大或者太小了,為了合理的使用內存,一定會對內存的大小做一個靈活的調整,那么realloc函數(shù)就可以做到對動態(tài)開辟內存大小的調整

realloc函數(shù)的出現(xiàn)讓動態(tài)內存管理更加靈活

void* realloc (void* ptr, size_t size); 

1.ptr是要調整的內存空間;

2.size是調整之后的新大??;

3.返回值為調整之后的內存起始位置;

4.realloc函數(shù)在調整原內存空間大小的基礎上,還會將原來內存中的數(shù)據(jù)移動到新的空間;

realloc函數(shù)在調整內存空間時存在兩種情況:

情況1:要調整的空間之后有足夠的空間來存放調整之后的大小

情況2:要調整的空間之后沒有足夠大的空間

如果是情況1,那么就在原有的內存之后追加新的空間,原來空間的數(shù)據(jù)不發(fā)生變化。

如果是情況2,原有空間之后沒有足夠多的空間,此時就會在堆空間上另找一個合適大小的連續(xù)空間來使用,這樣函數(shù)返回的是一個新的內存地址 

 并且realloc函數(shù)還會將原空間的數(shù)據(jù)移動到新的空間。

如果realloc函數(shù)在堆區(qū)中都找不到一塊合適的空間,則會返回NULL指針。        

realloc的使用:

int main()
{
	int* p = (int*)calloc(10, 4);
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	p = realloc(p, 1000);
	if (p == NULL)
	{
		perror("realloc");
		return 1;
	}
	free(p);
	p = NULL;
	return 0;
}

其次,realloc函數(shù)還能使原有空間變小:

使用:

int main()
{
	int* p = (int*)calloc(10, 4);
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	p = realloc(p, 20);
	if (p == NULL)
	{
		perror("realloc");
		return 1;
	}
	free(p);
	p = NULL;
	return 0;
}

內存情況:

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

3.1對NULL指針的解引用操作

 這里編譯器直接把對NULL指針的解引用操作給取消掉了,如果在其他的編譯器下運行,可能會出現(xiàn)問題,所以一定要對動態(tài)開辟內存函數(shù)的返回值進行一個NULL指針的判斷。

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

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = i;
	}
	free(p);
	p = NULL;
	return 0;
}

其中*(p + 10) = 10;時對動態(tài)開辟的空間進行了一個越界訪問了,編譯器直接報錯

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

對棧區(qū)上的空間使用free:

int main()
{
	int a = 0;
	free(&a);
	return 0;
}

此時編譯器也會給出一個錯誤 

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

int main()
{
	int* p = (int*)malloc(40);
	p++;
	free(p);
	return 0;
}

此時p沒有指向動態(tài)開辟內存的起始位置

編譯器同樣給出了一個錯誤

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

int main()
{
	int* p = (int*)malloc(40);
	free(p);
	free(p);
	return 0;
}

 p已經(jīng)釋放過了

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

在向內存申請了一塊空間之后沒有對其進行釋放會造成內存泄漏的問題

會迅速吃滿你的內存

int main()
{
	while (1)
	{
		malloc(40);
	}
	return 0;
}

 如圖:

如果程序在沒有結束之前申請的內存都沒有進行釋放的話,就會出現(xiàn)內存泄漏的問題。所以在申請好一塊內存之后要記得對其進行釋放。

總結:

忘記釋放不再使用的動態(tài)內存開辟的空間就會造成內存泄漏的問題,而且動態(tài)開辟的空間要正確釋放。

4.練習

4.1練習1

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

請問運行Test 函數(shù)會有什么樣的結果?

先創(chuàng)建了一個字符指針變量賦值為NULL,然后調用函數(shù)GerMemory,調用函數(shù)時形參只是一份對實參的臨時拷貝,函數(shù)調用時,申請了一塊動態(tài)開辟內存,但是并沒有返回p,p在函數(shù)調用結束后銷毀了,所以此時str指向的還是NULL,strcpy使用時對NULL指針進行了解引用,造成了非法訪問,野指針的問題,也造成了動態(tài)內存錯誤

4.1練習2

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

請問運行Test 函數(shù)會有什么樣的結果?

調用GetMemory函數(shù)時在棧區(qū)開辟了一塊數(shù)組的空間,而在函數(shù)調用結束后數(shù)組開辟的空間已經(jīng)被回收了,str接收了p的值,而p所指向的空間已經(jīng)被回收了,所以p所指向的值也會發(fā)生變化,所以此時printf(str);打印的會是未知的結果

4.3練習3

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

請問運行Test 函數(shù)會有什么樣的結果?

 Getmemory函數(shù)時傳址調用,將申請的動態(tài)開辟內存空間的起始位置地址給了str,所以能夠正常訪問開辟的內存。不過沒有進行free會造成內存泄漏的問題。

4.4練習4

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

請問運行Test 函數(shù)會有什么樣的結果?

此時已經(jīng)str所指向的動態(tài)內存空間已經(jīng)釋放掉了,會造成非法訪問。

5.C/C++程序的內存開辟

C/C++程序內存分配的幾個區(qū)域:

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

2.堆區(qū):一般有程序員分配,若程序員不釋放,程序結束時可能由OS回收,分配方式類似于鏈表。

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

4.代碼段:存放函數(shù)體的二進制代碼

實際上普通的局部變量是在棧區(qū)分配空間的,棧區(qū)的特點是在上面創(chuàng)建的變量出了作用域就銷毀,但是被static修飾的變量存放在數(shù)據(jù)段,數(shù)據(jù)段的特點是,在上面創(chuàng)建的變量,直到程序結束才銷毀,所以static修飾的變量生命周期變長了。

總結

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

相關文章

  • C++中智能指針如何設計和使用

    C++中智能指針如何設計和使用

    智能指針(smart pointer)是存儲指向動態(tài)分配(堆)對象指針的類,用于生存期控制,能夠確保自動正確的銷毀動態(tài)分配的對象,防止內存泄露,需要的朋友可以參考下
    2012-11-11
  • C++中的Lambda表達式及表達式語句

    C++中的Lambda表達式及表達式語句

    這篇文章主要介紹了C++中的Lambda表達式及表達式語句,表達式這個概念在C++中屬于比較細節(jié)的知識了,很多時候我們只用知道怎么用,對于編譯器內部怎么處理我們并不關心;并且關于左值和右值這個概念,也是C++比較深的一個小知識點,需要的朋友可以參考一下
    2021-12-12
  • C語言實現(xiàn)鏈隊列

    C語言實現(xiàn)鏈隊列

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)鏈隊列,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • C++實現(xiàn)神經(jīng)BP神經(jīng)網(wǎng)絡

    C++實現(xiàn)神經(jīng)BP神經(jīng)網(wǎng)絡

    這篇文章主要為大家詳細介紹了C++實現(xiàn)神經(jīng)BP神經(jīng)網(wǎng)絡,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • vs code 配置python虛擬環(huán)境的方法

    vs code 配置python虛擬環(huán)境的方法

    這篇文章主要介紹了vs code 配置python虛擬環(huán)境的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • 教你用Matlab制作黃金礦工小游戲

    教你用Matlab制作黃金礦工小游戲

    黃金礦工作為經(jīng)典的單機小游戲,一直深受大家的喜愛。本文將用Matlab制作這一款經(jīng)典的游戲,文中的實現(xiàn)步驟講解詳細,感興趣的可以了解一下
    2022-03-03
  • 基于VC實現(xiàn)的網(wǎng)絡監(jiān)聽功能程序實例

    基于VC實現(xiàn)的網(wǎng)絡監(jiān)聽功能程序實例

    這篇文章主要介紹了基于VC實現(xiàn)的網(wǎng)絡監(jiān)聽功能程序,需要的朋友可以參考下
    2014-07-07
  • C++高精度算法的使用場景詳解

    C++高精度算法的使用場景詳解

    在我們進行計算的過程中,經(jīng)常會遇到幾十位,甚至幾百位的數(shù)字的計算問題,也有可能會遇到小數(shù)點后幾十位,幾百位的情況,而我們面對這樣的情況下,long long  和 double 的數(shù)據(jù)范圍顯然是不夠使用的了。因此這時,我們就需要引入一個新的算法,叫做高精度算法
    2022-09-09
  • 基于memset()函數(shù)的深入理解

    基于memset()函數(shù)的深入理解

    本篇文章是對memset()函數(shù)又進行了深一步的了解,需要的朋友參考下
    2013-05-05
  • VS2019中CMake項目的簡單使用方法

    VS2019中CMake項目的簡單使用方法

    這篇文章主要介紹了VS2019中CMake項目的簡單使用方法,需要的朋友可以參考下
    2020-02-02

最新評論

精河县| 柯坪县| 廊坊市| 屏东市| 静安区| 福清市| 郯城县| 永安市| 邯郸县| 台东市| 昌邑市| 唐河县| 东乡县| 巧家县| 江达县| 英山县| 抚顺市| 沧州市| 岑溪市| 东台市| 循化| 松原市| 广西| 红原县| 集安市| 云浮市| 馆陶县| 太原市| 澳门| 昭觉县| 商水县| 孟村| 陵水| 望江县| 桃源县| 永寿县| 东光县| 屏边| 宁城县| 芜湖市| 岳池县|