天天看點

【C語言】動态記憶體配置設定動态記憶體配置設定存在的原因動态記憶體函數

目錄

  • 動态記憶體配置設定存在的原因
  • 動态記憶體函數
    • 1. malloc 和 free
    • 2. calloc
    • 3.realloc

動态記憶體配置設定存在的原因

首先我們知道記憶體開辟的方式有:

int a = 0;//在棧上開辟4個位元組的空間
char ch[10] = {0};//在棧上開辟10個位元組的連續空間
           

上述的兩種方式有兩個特點:

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

2)數組在聲明時需要明确其大小,即數組長度,其記憶體在編譯時配置設定。

但是在實際應用中我們所需要的不止是一個固定大小的數組,而常常需要堆數組的長度進行修改,而數組在編譯時開辟空間的方式就不能滿足我們的需求了,這時我們就需要用到動态記憶體配置設定了。

動态記憶體函數

我們常用的動态記憶體函數有malloc,free,calloc,realloc等等

1. malloc 和 free

C語言給出了這麼一個動态記憶體開辟的函數:

void* malloc (size_t size);
           

這個函數會向記憶體申請一塊連續可用的空間,同時傳回指向這塊空間的指針。

在這裡我們來了解一下記憶體的大緻分布:記憶體分為棧,堆,靜态區等等部分。其中棧是臨時變量所存儲的空間,同時函數開辟空間時也是在棧中進行的,這被稱為函數棧幀,有機會的話後面會介紹的;堆就是動态記憶體開辟時所申請的空間;而靜态區是靜态變量開辟時所申請的空間,比如全局變量,static修飾的變量等。

【C語言】動态記憶體配置設定動态記憶體配置設定存在的原因動态記憶體函數

而malloc函數向記憶體申請空間就是在堆申請的。

malloc函數在申請空間時會有兩種情況:

1)若空間開辟成功,則傳回指向該空間的指針。

2)若空間不足,開辟失敗,則傳回NULL。

而函數的傳回值為void* ,是因為malloc在開辟空間時并不知道所要開辟空間的類型,在具體使用時使用者需要自己決定;其次,若size為0,malloc的行為是标準未定義的,具體取決于編譯器。

與malloc相對的,C語言提供了另外一個函數free,是專門用來做動态記憶體的釋放和回收的,其函數原型如下:

void free (void* ptr);
           

對于free函數有兩點需要注意:

1)若所free的指針不是指向動态開辟的空間,那麼free的行為是标準未定義的。

2)若所free的指針是NULL,則什麼也不會發生。

malloc和free都聲明在<stdlib.h>頭檔案中。

需要注意的是malloc和free通常是成對使用的,否則會造成記憶體洩露。

舉個例子:

int main()
{
	int* a = (int*)malloc(sizeof(int) * 10);//向記憶體申請10個int位元組的連續空間
	if (a == NULL)//判斷記憶體申請是否成功
	{
		printf("malloc fail");
		exit(-1);
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		a[i] = i;
	}
	free(a);//釋放a所指向的記憶體空間
	a = NULL;//free函數并不會将a置空,那麼此時a為野指針,需要我們手動置空
	return 0;
}
           

2. calloc

C語言同時還提供了calloc函數來實作動态記憶體配置設定,其函數原型為:

void* calloc (size_t num, size_t size);
           

calloc函數的功能是向記憶體申請num個size大小的連續空間,并在申請的同時将這些空間初始化為0;與malloc不同的是calloc會在傳回位址之前将申請的空間中的每個位元組初始化為0,也就是說若我們在申請空間時需要初始化所申請的空間,calloc可以友善我們的操作。比如:

`int main()
{
	int* a = (int*)calloc(10, sizeof(int));
	if (a == NULL)
	{
		printf("calloc fail");
		exit(-1);
	}
	free(a);
	a = NULL;
	return 0;
}`
           

在這個函數中,calloc向記憶體申請空間後的連續40個位元組空間内容均被初始化為0。

【C語言】動态記憶體配置設定動态記憶體配置設定存在的原因動态記憶體函數

3.realloc

從功能上将上述的malloc和calloc函數都并未實作可以是記憶體動态改變的功能,它們都隻是向記憶體申請了一片固定的空間,而實際上想要真正對記憶體進行動态的調整就需要realloc函數,其函數原型為:

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

參數中的ptr為要調整的記憶體空間的起始位址;size為調整後空間的新大小;

函數的傳回值為調整後的空間的起始位址。

函數在調整記憶體空間時,有可能會将原記憶體空間的内容轉移到新的記憶體空間上,這就與realloc調整空間可能出現的兩種情況有關:

1)原記憶體空間後的空間足夠大,足以調整。

2)原記憶體空間後沒有足夠的空間,不足以開辟所需要的空間。

【C語言】動态記憶體配置設定動态記憶體配置設定存在的原因動态記憶體函數

由于上述兩種情況的存在,realloc在具體使用過程中需要注意一些:

int main()
{
	int* a = (int*)malloc(sizeof(int) * 10);//向記憶體申請40個位元組的連續空間
	if (a == NULL)
	{
		printf("malloc fail");
		exit(-1);
	}
	int* tmp = (int*)realloc(a, sizeof(int) * 20);//調整原空間使其擴大為80個位元組
	if (tmp == NULL)
	{
		printf("realloc fail");
		exit(-1);
	}
	a = tmp;
	free(a);
	a = NULL;
	return 0;
}
           

上述程式中的tmp是必要的,這是因為如果原記憶體後沒有足夠大的空間,那麼若代碼改為

a = (int*)realloc(a,sizeof(int)*20);

a在realloc函數執行過程中會改變指向,緻使realloc找不到原記憶體,進而無法将原記憶體空間的資料拷貝到新開辟的記憶體空間中,導緻資料丢失,是以需要用一個臨時變量來記錄新開辟的記憶體空間,在修改原指針。

另外一點,若realloc中的ptr參數為NULL,那麼realloc函數就和malloc函數的功能一樣了。