malloc、calloc和realloc區別

康_同學發表於2020-11-09

   在C語言中,記憶體分為四塊儲存區域:棧區,堆區,靜態儲存區,程式碼區。堆記憶體是一種在需要時申請,在不需要時釋放的記憶體塊,都是由程式設計師來完成的。

主要探討一下動態分配堆記憶體的庫函式,這些庫函式包含在標頭檔案<stdlib.h>中。

1.malloc函式

原型為 void* malloc(size_t size);這個函式向記憶體申請一塊連續可用的空間,並返回指向這塊空間的指標。

演示示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	/* 1. malloc返回的是void *型別,在需要時候的時候要做一個適合目標指標型別的轉換,比如這裡強制型別轉換成int *;
	如果是 char *p = (char *)malloc(10);
	*/
	int *p = (int *)malloc(10 * sizeof(int));
	//int *p = (int *)malloc((size_t)(1024*1024*1024*2));  //執行此句就會執行失敗,
	//所以malloc之後一定要做一個是否申請記憶體成功的判斷
	if (!p)
	{
		printf("malloc 失敗, p = %p\n", p);
		exit(1);
	}

	// 2.malloc分配的記憶體它的值是隨機
	printf("malloc剛申請的一段記憶體其值是:\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	printf("\n");


	// 賦初值
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	printf("初始化後的資料:\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	printf("\n");

	printf("free前的p = %p\n", p);

	free(p);
	//p = NULL;


	// 3. 測試free後指向的記憶體區域數值
	printf("free後的p_a = %p\n", p);
	printf("測試free後指向的記憶體區域數值:\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	printf("\n");
	/*
	printf("測試free還往其指向的記憶體空間寫資料:\n");
	for (int i = 0; i < 10; i++)
	{
	*(p + i) = i; //往free後的空間寫資料,程式出錯
	}
	*/
	printf("程式結束\n");
	return 0;
}

2.calloc函式

原型為void*calloc(size_t num,size_t size);函式的功能是為num個大小為size的元素開闢一塊空間,並且把空間的每個位元組初始化為0。

演示示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int main()
{
	//int *p = (int *)malloc(10*sizeof(int));
	// 1. calloc的引數和malloc有區別
	int *p = (int *)calloc(10, sizeof(int));

	if (!p)
	{
		printf("malloc 失敗, p_a = %p\n", p);
		exit(1);
	}

	// 2. calloc申請的一段記憶體空間其值都被初始化為0
	printf("calloc剛申請的一段記憶體其值是:\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	printf("\n");



	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	printf("初始化後的資料:\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	printf("\n");

	printf("free前的p = %p\n", p);

	free(p);
	//p_a = NULL;

	// 3. 測試free後指向的記憶體區域數值
	printf("free後的p = %p\n", p);
	printf("測試free後指向的記憶體區域數值:\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

3.realloc函式

原型為void* realloc(void*ptr,size_t size); 給一個已經分配了地址的指標重新分配空間,引數ptr為原有的空間地址,size是重新申請的地址長度,返回值為調整之後的記憶體起始位置。

realloc在調整記憶體空間存在兩種情況:

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

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

當時情況1的時候,要擴充套件記憶體就直接在原有記憶體之後直接追加空間,原來空間的資料不發生變化。當是情況2的時候,原有空間之後沒有足夠多的空間時,擴充套件的方法是:在堆空間上另找一個合適大小的連續空間來使用,這樣函式返回的是一個新的記憶體地址。

演示示例:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main()
{
	int *p = (int *)malloc(10 * sizeof(int));     //申請10*sizeof(int)位元組的空間

	// 1. 給p_a指向的記憶體做初始化
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;           // 賦值
	}

	printf("\n初始化p指向記憶體的數值:\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}

	// 1. 擴充資料,從10個int變為15個int
	printf("\n擴充之前p = %p\n", p);
	p = (int *)realloc(p, 15 * sizeof(int));
	printf("擴充之後p = %p\n", p);
	printf("\n擴充之後的的數值:\n");	// 擴充後地址空間是很有可能發生變化的
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", *(p + i));	// 原有的內容的數值沒有變化, 但擴充之後的數值是不確定的
	}

	// 2. 縮減資料
	p = (int *)realloc(p, 5 * sizeof(int));
	printf("\n縮減之後p = %p\n", p);
	printf("\n縮減之後的的數值:\n");	// 
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", *(p + i));	//  縮減記憶體後被縮減部分的資料有變化
	}

	// 測試越界使用
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;           // 賦值
	}

	free(p);
	p = NULL;     // 記憶體釋放後將p置為NULL

	printf("程式結束\n");
	return 0;
}

4.free函式

申請的記憶體最終需要通過函式free來釋放.void free(void*ptr);prt=NULL;

 

 

相關文章