动态内存管理

动态内存管理

1.为什么要有动态内存分配

int n=10;//4个字节
char c;//1个字节
char arr[20];//20个字节
int arr[20];//80个字节

上面这申请内存空间的方式

一旦申请好,大小就无法调整

1.2动态内存的四个函数

1.malloc——向内存申请一块连续可用的空间,并返回指向这块空间的指针(返回起始地址)

void*malloc(size_t size)
//size 的单位是字节

如果开辟成功,返回开辟好空间的指针(就是起始地址)
如果开辟失败,返回NULL指针,因此malloc的返回值要检查好
void*,不知道要开辟什么类型的空间,由使用者自己决定

#include<stdlib.h>
int main()
{
	int*p=(int*)malloc(20);//使用时自己决定类型
	if(p==NULL)//判断开辟成功没有
	{
		perror("malloc");//空指针,开辟失败,报错
		return 1}
	int i=0;
	for(i=0;i<5;i++)
	{
		*(p+i)=i+1;
	}
	return 0;
}

注意:要包含stdlib.h文件
在这里插入图片描述

2.free——专门用来做动态内存的释放和回收

void free(void* ptr);//参数是个指针变量,给他传个地址过去
//释放哪块空间,就把那个空间的起始地址传过去

free只能释放动态开辟的,指向的空间若不是动态开辟的,那free的函数行为是未定义的

如果传的是空指针,那free什么都不做

free也要包含头文件stdlib.h
在这里插入图片描述

#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(20);//使用时自己决定类型
	if (p == NULL)//判断开辟成功没有
	{
		perror("malloc");//空指针,开辟失败,报错
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;//这样写就是让p就是起始地址
	}
	//释放内存 free
	free(p);//传递给free的是要释放的空间的起始地址
	p = NULL;//避免P成为野指针,释放完就设成空指针是好的编程习惯
	return 0;
}

3.calloc——也还用来动态申请内存的

void*calloc (size_t num,size_t size)

开辟num个大小为size的空间,并把空间初始化为0

int main()
{
	int*p=(int*)malloc(5 * sizeof(int));//malloc总大小
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	int* p = (int*)calloc(5 , sizeof(int));//calloc中间就是逗号了

	return 0;
}

malloc和calloc就这点区别,malloc不初始化

剩下的使用都一样,都相当于数组
在这里插入图片描述
calloc就是会把空间初始化为0

4.realloc——让动态内存管理更灵活

void*realloc (void*ptr,size_t size)

ptr——是要调整的内存地址
size——调整之后的新大小
返回调整之后的内存起始地址
在这里插入图片描述

情况1.在后面分配20个字节就行
情况2.后面不够20,直接在后面找个地方申请40个
对于情况2::
1.在堆区内存在找一个新的空间,满足大小要求
2.会将原来空间的数据拷贝一份到新的空间
3.释放2旧的空间(realloc自己释放,不用free)
4.返回新的内存空间的起始地址
情况3.调整失败,返回NULL

#include<stdlib.h>
#include<stdio.h>
//int main()
//{
//	int* p = (int)malloc(20);//使用时自己决定类型
//	if (p == NULL)//判断开辟成功没有
//	{
//		perror("malloc");//空指针,开辟失败,报错
//		return 1;
//	}
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		*(p + i) = i + 1;
//	}
//	//释放内存 free
//	free(p);
//	p = NULL;
//
//	return 0;
//}
//向内存申请5个整型空间
//int main()
//{
	//int*p=(int*)malloc(5 * sizeof(int));//malloc总大小
	//if (p == NULL)
	//{
	//	perror("malloc");
	//	return 1;
	//}
//	int* p = (int*)calloc(5 , sizeof(int));//calloc中间就是逗号了
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		printf("%d", *(p + i));
//	}
//	free(p);
//	p = NULL;
//	return 0;
//}
int main()
{
	int* p = (int*)malloc(5 * sizeof(int));//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;//确定调整空间大小成功了,再把40个字节给p,要不然失败了,之前的20个也没了
	}
	return 0;
}

在这里插入图片描述

int main()
{
	int* p = (int*)malloc(5 * sizeof(int));//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;//确定调整空间大小成功了,再把40个字节给p,要不然失败了,之前的20个也没了
		int i = 0;
		for (i = 5; i < 10; i++)
		{
			*(p + i) = i + 1;//给后面20个字节
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ",*(p+i));
		}
		free(p);
		p = NULL;
	}
	else {
		perror("realloc");
		free(p);
		p = NULL;
	}
	
	return 0;
}

在这里插入图片描述

常见的动态内存管理的错误

1.对空指针的解引用操作——malloc的返回值一定要判断

int main()
{
	int* p = (int*)malloc(20);
	*p = 20;//没有判断返回值
	return 0;
}

修改后

int main()
{
	int* p = (int*)malloc(20);
	if(p==NULL)
	{
	perror("malloc");
	return 1;
	}
	*p = 20;
	return 0;
}

在这里插入图片描述

在这里插入图片描述

2.对动态开辟空间的越界访问

//对动态开辟空间的越界访问
#include<stdlib.h>
void test()
{
	int i = 0;
	int* p = (int*)malloc(10 * sizeof(int));
	if (NULL == p)
	{
		exit(EXIT_FAILURE);
	}
	for (i = 0; i <= 10; i++)//i<10就可以了,i<=10越界
	{
		*(p + i) = i;//当i是10的时候越界访问 ,会指向第11个
	}
	free(p);
}
int main()
{
	test();
	return 0;
}

在这里插入图片描述

3.对非动态开辟内存使用free释放

void test()
{
	int a = 10;
	int* p = &a;
	free(p);
	p=NULL;//a在栈区,只是个局部变量,非动态开辟
}

4.使用free释放动态内存空间的一部分

//free释放动态开辟的一部分
int main()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return 1;
	}
	int i=0;
	for (i = 0; i < 5; i++)
	{
		*p = i+1;
		p++;//p一开始指向的是100空间的起始地址
	}
	free(p);//这里的p不再是动态申请的内存的起始位置
	p = NULL;
	
	return 0;
}

在这里插入图片描述

5.对同一块动态内存多次释放

//同一块内存多次释放
void test()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);
}

可以修改为

//同一块内存多次释放
void test()
{
	int* p = (int*)malloc(100);
	free(p);
	p=NULL;
	free(p);//这里p是空指针在释放没问题,free什么都不用做
}

6.动态内存忘记释放(内存泄漏)

//忘记释放
void test()
{
	int* p = (int*)malloc(100);
	if (NULL != p)
	{
		*p = 20;
	}
}//没有释放后面在想用找不到了,存到局部变量里了,生命周期完成后,局部变量销毁

int main()
{
	test();
	while (1);
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值