动态内存管理---你可能会忽略的小技巧

引言:动态内存管理是学习C语言当中非常重要的一环,因为他涉及到计算机的空间储存管理,是一种新的开辟空间的方式

在此前我们开辟空间,都是在计算机的栈区,而用动态内存管理函数开辟的空间则在栈区,这让我们可以自由调节自己开辟的空间来使用

int a = 8;//在栈空间上开辟2个字节
char arr[10] = {0};//在栈空间上开辟10个字节的连续空间

遗憾的是,以上两种开辟空间的方式,有两大特点

1.空间开辟的大小是固定的,在确定以后修改不了

2.数组在声明的时候,必须要指定数组长度,数组空间一旦确定下来就无法改变了。

这样的空间开辟方式让我们对于空间大小的灵活使用并不利好,所以我们需要一中可以灵活申请和释放空间的方式------动态内存。

1.malloc和free

学习过动态内存管理的大家都很熟悉这两个函数,一个用来申请开辟空间的大小,一个用来释放自己开辟的空间

void* malloc (size_t size);//用于开辟size个字节空间,返回值是void*,返回的是开辟的空间的首地址。
//因为在开辟函数之前malloc函数还不知道你需要用作什么样的数据类型,所以用void*来接收(在上一期有论述到噢),要用的时候自己定义
void free (void* ptr);//用于释放内存

tips:释放空间非常重要!!!

那么下面,我来给大家介绍一下他们是如何打配合的

#include <stido.h>
#include <stdlib.h>//使用动态内存函数,需要包含这个头文件
int main()
{
	int* p = (int*)malloc(20);//20 个字节 - 存放5个整数,或者可以int*p= (int*)malloc(sizeof(int)*5);
	if (p == NULL)
 	//因为开辟空间是会出现失败的情况的,而失败时,将会返回NULL,在申请内存后进行一个判断,有利于我们清楚自己写的程序有无出现状	况,是个好习惯噢!
	{
		perror("malloc");//这个函数可以反馈程序运行时出现的错误
		return 1;
	}
	//使用空间
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;
	}

	//释放内存
	free(p);//传递给free函数的是要释放的内存空间的起始地址
	p = NULL;//最后再把用完的空间设置为NULL,防止它成为野指针

	return 0;
}

2.calloc和realloc

void* calloc (size_t num, size_t size);//calloc的使用方式和malloc几乎一模一样,知识 calloc多了一个功能:将你所开辟的空间都初始化为0
void* realloc (void* ptr, size_t size);//realloc就比较关键啦,因为它可以动态的帮我们任意更改开辟空间的大小
//ptr是要调整的内存地址,size是调整之后新大小,返回值为调整之后的内存起始位置。

realloc的使用使得我们对于空间管理可以更加的灵活,但是我们需要注意它开辟空间的两种情况

情况1:当拓展的内存后面有足够的空间可以开辟,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化

情况2:原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找⼀个合适大小的连续空间来使⽤。

​ 这样函数返回的是⼀个新的内存地址

下面画了一张图帮助大家理解

在这里插入图片描述

#include<stido.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(5 * sizeof(int));//开辟一个5个整型空间,20字节
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i+1;
	}
	//希望将空间调整为40个字节
	int*ptr = (int*)realloc(p, 40);
	if (ptr != NULL) //调整成功
	{
		p = ptr;
		int i = 0;
		for (i = 5; i < 10; i++)
		{
			*(p + i) = i + 1;
		}

		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
		free(p);//记得释放内存
		p = NULL;
	}
	else //调整失败
	{
		perror("realloc");
		free(p);//也要释放内存
		p = NULL;
	}

	return 0;
}
//tips:realloc函数可以完成和malloc一样的功能
int main()
{
	realloc(NULL, 20);//=== malloc(20);
	return 0;
}

3.柔性数组(可长可短的数组)---------动态内存与结构体的配合

特点:
结构中的柔性数组放在结构体最后一个成员,且前⾯必须至少⼀个其他成员。
sizeof返回的这种结构大小不包括柔性数组的内存。
包含柔性数组成员的结构使用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

struct S
{	char c;
	int n;
	int arr[];//柔性数组
};

int main()
{	struct S* ps = (struct S*)malloc(sizeof(struct S) + 5*sizeof(int));
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	ps->n = 100;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}
	//调整空间
	struct S* ptr = (struct S*)realloc(ps, sizeof(struct S)+10*sizeof(int));
	if (ptr != NULL)
	{
		ps = ptr;
	}
	
 	for (i = 0; i < 10; i++)//此时我们可以访问10个整型,不会越界
	{
		ps->arr[i] = i;
	}

	free(ps);//释放
	ps = NULL;

	return 0;
}

4.内存泄漏问题

大家可以来看看以下代码有没有什么问题

void test()
{
	int *p = (int *)malloc(100);
	if(NULL != p)
	{
		*p = 20;
	}
}
int main()
{
	test();
	while(1);
}
return 0;

}


## 4.内存泄漏问题

大家可以来看看以下代码有没有什么问题

```c
void test()
{
	int *p = (int *)malloc(100);
	if(NULL != p)
	{
		*p = 20;
	}
}
int main()
{
	test();
	while(1);
}

以上代码,p是局部变量,在函数里使用后就销毁了,你再也找不到他了,但是你又用它开辟了一段空间,并且没有释放,程序运行的时候就一直占用那片空间内存,你没法使用了,也就是造成了内存泄漏了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值