C语言动态内存管理malloc、calloc、realloc、free函数的讲解

目录

一.为什么存在动态内存管理:

二、动态内存函数的介绍:

1.动态开辟函数——malloc函数

1.1.函数声明和作用:

1.2.函数使用实例:

2.释放动态空间函数——free函数

2.1.free函数注意事项:

2.2.free函数使用实例:

3.动态开辟函数——calloc函数

3.1.函数的声明和作用:

3.2.函数使用实例:

4.动态开辟函数——realloc(最主要、最常用):

4.1.注意事项:

4.2.函数声明与作用:

4.3.函数返回值:有三种情况

4.4.函数使用实例:


一.为什么存在动态内存管理:

我们知道,在此之前向内存申请空间的方式有以下两种:(变量和数组)

但这两种方法有几个缺陷

①:空间开辟大小是固定的;

②:数组在声明的时候,必须指定数组的长度,它所需要的内存在编译时分配;

但是由于空间的需求,不仅仅是上述两种情况,有时候我们需要的空间大小在程序运行的时候才知道,那数组的编译时开辟空间的方式就不合适了。

假设数组大小为100,但有101个元素就塞不下;只有10个元素又太浪费空间了。

所以这时候只能试试动态分配了。

二、动态内存函数的介绍:

1.动态开辟函数——malloc函数

1.1.函数声明和作用:
void* malloc (size_t size);

①:函数作用:向内存申请一块可用的连续的空间,返回值为这块空间的起始地址;

②:函数参数:类型为size_t,即该函数一次申请size个字节的空间,但不会初始化该空间内容,如果size==0,那么malloc的行为是未定义的,取决于编译器;

③:返回值是void*,返回规则如下:

④:该函数包含头文件<stdlib.h>中。

⑤:动态内存函数申请空间都是在堆区上面申请,如下图:

1.2.函数使用实例:
#include<stdio.h>
#include<stdlib.h>

int main()
{
	//要什么类型的空间,就用什么类型的指针接收
	//注意函数返回值为void*,所以记住强制类型转换
	int* p = (int*)malloc(40);
	//判断申请空间是否成功
	if (p == NULL)
	{
		perror("malloc");//打印申请失败的原因
		return 1;
	}
    //使用空间
	int i = 0;
	for (i = 0; i < 4; i++)
	{
		p[i] = i;
		printf("%d ", p[i]);
	}
	return 0;
}

2.释放动态空间函数——free函数

注意:这些动态开辟函数申请内存空间,当程序退出时,会还给操作系统,但当程序不退出,动态开辟的内存不会主动释放,这时就需要用到函数free()来释放。

2.1.free函数注意事项:

①:函数声明:

void free (void* ptr);

②:该函数包含在头文件<stdlib.h>中。

2.2.free函数使用实例:

该函数使用方法非常简单,参数只需要给动态开辟的变量即可,如下:

这里值得注意的是,free函数释放空间后,不会改变指针p的值,所以此时p还是指向这块空间,但该空间已被释放,所以此时p是野指针,所以我们要把p指针置空

3.动态开辟函数——calloc函数

3.1.函数的声明和作用:
void* calloc (size_t num, size_t size);

①:函数的作用:该函数是动态开辟num个大小为size的空间,并且把空间的每个字节初始化为0;

②:返回值和malloc相同,开辟成功返回这块空间的起始地址;开辟失败返回NULL。

③:与malloc函数的区别是:该函数为把空间的每个字节初始化0。

④:

3.2.函数使用实例:

int main()
{
	//动态开辟五个整型大小的空间
	int* p = (int*)calloc(5, sizeof(int));
	//检查是否开辟成功
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//使用空间
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", p[i]);
	}
	//释放空间
	free(p);
	p = NULL;
	return 0;
}

运行结果:

4.动态开辟函数——realloc(最主要、最常用):

4.1.注意事项:

realloc函数的出现让动态内存管理更加灵活。

有时我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,为了合理使用内存,我们就可以用realloc函数动态开辟内存,以便对内存的大小做灵活调整。

4.2.函数声明与作用:
void* realloc (void* ptr, size_t size);

①:参数介绍:

第一个参数void*,是指需要调整大小的空间,是之前通过malloc、calloc、realloc函数开辟好的;

第二个参数size_t szie,是指调整后的新的空间大小,单位为字节;

②:当第一个参数ptr为空指针时,效果和malloc相同。

4.3.函数返回值:有三种情况

情况一:若str后面还有足够的连续空间,则返回值为str的起始空间。

情况二:若str后面没有足够的连续空间,则realloc函数会重新找一份足够大的新空间;将旧空间的内容拷贝到新空间;然后释放掉旧空间;最后返回新空间的起始地址。

情况三:开辟失败,返回NULL。

4.4.函数使用实例:
int main()
{
	//先用malloc开辟5个整型的空间
	int* p = (int*)malloc(20);
	//检查malloc是否开辟成功
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//开辟成功后,赋值1,2,3,4,5
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p[i] = i + 1;
	}
	//用realloc扩容五个整形的空间,所以新空间为40字节
	//注意这里别用上面的指针p接收,
	//因为如果realloc开辟失败,就会返回空指针给指针p
	//指针p改变了,那么之前动态开辟的空间就找不到了,就会存在内存泄漏
	int* str =(int*) realloc(p, 40);
	//检查是否开辟成功
	if (str == NULL)
	{
		perror("realloc");
		return 1;
	}
	//开辟成功后再赋值给指针p,然后将str置零
	p = str;
	str = NULL;
	//检测是否将旧空间的数据拷贝到新空间
	for (i = 0; i < 5; i++)
	{
		printf("%d ", p[i]);
	}
    //释放
    free(p);
    p = NULL;
	return 0;
}

运行结果:

本次知识到此结束,关于动态内存的知识还没有结束,未完待续!

猜你喜欢

转载自blog.csdn.net/hffh123/article/details/133324322