C语言之动态内存管理

C语言的动态内存管理这个概念是我们第一次接触,想要学好动态内存,学好malloc、calloc、relloc、和free这四个函数是必不可少的。


目录

1.为什么存在动态内存分配

2.动态内存函数介绍

2.1malloc函数(申请一块内存空间)

2.1.1函数介绍

2.1.2代码示例

2.2free函数(释放申请的动态内存的空间)

2.2.1函数介绍

2.2.2代码示例

2.3calloc函数(申请一块内存空间)

2.3.1函数介绍

2.3.2代码示例

2.4realloc函数(对动态开辟的内存大小进行调整,即重新分配内存,它也可以用来开辟空间)

2.4.1函数介绍

2.4.2代码示例

2.4.3realloc函数用来开辟的情况


1.为什么存在动态内存分配

在了解动态内存之前,我们要知道数据被申请后存储在内存哪里,如图所示:

1.我们平时的内存开辟方式是在栈空间上开辟空间,这种开辟方式有两个特点:

    空间开辟大小是固定的;

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

2.但是对于空间的需求,不仅仅是上述的情况,有时候我们需要的空间大小在运行的时候才会知道,那数组的编译时开辟空间的方式就不能满足了

这时候就需要我们动态内存开辟。

2.动态内存函数介绍

2.1malloc函数(申请一块内存空间)

2.1.1函数介绍

1.头文件:#include<stdlib.h>

2.函数格式:void *malloc( size_t size );

3.malloc函数向内存申请一块连续可用的空间,并返回指向这块空间的指针(首地址)

4.如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查

5.返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候由使用者自己来决定,通常用到强制类型转换

6.如果size为0个字节,malloc函数的行为是标准未定义的,取决于编译器,同时,这也是无意义的

2.1.2代码示例

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

int main()
{
	//申请40个空间的字节,用来存放10个整型
	int* p = (int*)malloc(40);
	//判断malloc函数是否开辟空间成功,如果成功,就往下执行程序;
	//如果失败,打印错误信息,并返回,结束代码
    //注意,这里开辟一块空间并不是百分百成功的,假若我们要申请一个无限大的空间,
    //malloc函数是无法开辟的,就会打印错误信息,打印Not enough space
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用动态开辟的这块内存
	int i = 0;
	for (i = 1; i <=10; i++)
	{
		*(p + i) = i;
		printf("%d ", *(p + i));
	}
	//这里是动态开辟内存的释放,我们在free函数中仔细说明
	free(p);
	p = NULL;
	return 0;
}

代码中,我们看到了free函数的使用,下面我们来介绍free函数

2.2free函数(释放申请的动态内存的空间)

2.2.1函数介绍

free函数和malloc、calloc、realloc都是成对使用的

1.头文件:#include<stdlib.h>

2.函数格式:void free( void *ptr);

3.free函数专门用来释放和回收动态内存

4.如果参数ptr指向的空间不是动态内存开辟的,那么free函数的行为是未定义的,free函数是无法释放非动态内存开辟的空间的

5.如果ptr此时是NULL指针,那么free函数什么也不做

2.2.2代码示例

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

int main()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	int i = 0;
	for (i = 1; i<=10; i++)
	{
		*(p + i) = i;
		printf("%d ", *(p + i));
	}
	//free函数,归还malloc开辟的空间
	free(p);
	p = NULL;
	return 0;
}

free函数主动归还malloc所开辟的空间但此时,p就变为了野指针,还存放这开辟空间的首地址,没有主动置空,所以需要我们把它置为空指针,防止非法访问

2.3calloc函数(申请一块内存空间)

2.3.1函数介绍

malloc函数和calloc函数都是申请一块内存空间,用法基本相同,只有细微差别

malloc函数申请到的空间没有初始化,直接返回起始地址;

calloc函数申请好空间后,会把空间初始化为0,然后返回起始地址

1.头文件:#include<stdlib.h>

2.函数格式:void *calloc( size_t num, size_t size );

3.num是要开辟元素的个数,size是开辟的每个元素的大小,也就是为num个大小为size的元素开辟一块内存空间,并把空间的每个字节初始化为0

2.3.2代码示例

int main()
{
	//为10个大小为int型的元素开辟一块空间
	int* p = (int*)calloc(10, sizeof(int));
	//判断calloc函数是否开辟空间成功
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i <10; i++)
	{
		//在这里直接打印,可以验证一下是否calloc函数把开辟好的空间初始化为0
		printf("%d ", *(p + i));
	}
	//free函数释放这块空间
	free(p);
	p = NULL;
	return 0;
}

2.4realloc函数(对动态开辟的内存大小进行调整,即重新分配内存,它也可以用来开辟空间)

2.4.1函数介绍

当我们发现动态申请的空间太小或者太大时,为了合理使用内存,我们要对内存的大小做灵活的调整,realloc函数就可以做到对动态开辟内存大小的调整

1.头文件:#include<stdlib.h>

2.函数格式:void *realloc( void *ptr, size_t size );

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

4.ptr是要调整的内存地址,size是调整之后的新大小,扩容后空间的总大小是整个动态开辟空间的总大小

5.函数返回值为调整之后内存起始位置,并不初始化

6.函数在调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间

7.realloc在调整内存空间时存在两种情况:

      待扩容的动态内存后有足够的空间

当它后面有足够的空间可以扩容时,直接在后边续上新的空间,返回旧的起始地址

      待扩容的动态内存后没有足够的空间

当后面没有足够空间可以扩容时,realloc函数会找一个满足空间大小的新的连续空间,把旧的空间的数据,拷贝到新空间前面的位置,并把旧的空间释放,同时返回新空间的首地址

我们用代码来讨论

2.4.2代码示例

//realloc函数

int main()
{
	//先使用malloc开辟一块大小为5个整型的空间
	int* p = (int*)malloc(sizeof(int) * 5);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;
	}
	//此时,我们发现空间不够,想要在开辟好的动态空间之后再增加5个整型空间
	//注意,这里扩容空间的总大小是整个动态开辟空间的总大小
	int* ptr = (int*)realloc(p, sizeof(int) * 10);
	//这里必须用一个新指针来接收realloc的返回值,不能用P,因为realloc函数可
	//能会扩容失败返回NULL,若用原来p指针接收,会把未扩容前已经放入空间的
	//数据丢失,不安全
	if (ptr != NULL)
		p = ptr;
	//使用扩容后的空间
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	//释放空间
	free(p);
	p = NULL;
	return 0;

}

我们发现打印出来的是我们最先存入的5个数据和5个随机值,也验证了realloc函数对所扩容出来的空间不进行初始化

2.4.3realloc函数用来开辟的情况

当函数传递的第一个参数为空指针(NULL)时,函数作业相当于malloc,向内存开辟一块动态空间,即:

int* p=(int*)realloc(NULL,40);

相当于

int* p=(int*)malloc(40);

这就是动态内存管理的基本知识,我们会在下期学习动态内存管理的一些需要注意的地方,我们下期再见!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月亮夹馍干

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值