动态内存管理(1)

我们目前学过的主要的两种内存开辟方式

一种是直接声明变量 比如 int a=0;

另一种是声明数组 比如 char arr[5]={0};

但是这两种方式都有缺点,

1.空间开辟大小是固定的。
2.数组在申明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整


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


C语言引入了动态内存开辟,让程序员自己可以申请和释放空间,就比较灵活了。

我们先来看第一个函数malloc

1,malloc

malloc

void* malloc (size_t size);

1.这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针,申请空间的大小单位是字节。


2.如果开辟成功,则返回一个指向开辟好空间的指针。


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


4.返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自
己来决定。


5.如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。

6.malloc返回的指针是void*类型的,因此我们再使用之前要强制类型转换成我们要用的类型

7.malloc的头文件是#include<stdlib.h>

8.malloc开辟的空间是位于堆区的

栈区:用于存放局部变量,局部数组,和形式参数
堆区:动态内存;malloc,realloc等等
静态区:全局变量和static修饰的静态变量

9.我们使用malloc申请的空间需要释放那就涉及到另外一共函数了,也就是free, 当然如果你没释放,当程序跑完,系统也会将其回收。

free

void free (void* ptr);

1.free函数用来释放动态开辟的内存。
2.如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
3.如果参数ptr是NULL指针,则函数什么事都不做。
4.malloc和free都声明在stdlib.h头文件中。

5一旦free后的指针是无法使用的,是野指针,非常危险,所以野指针我们要将其至成空指针

6.free无法对同一块空间进行多次释放,第二次释放的就是野指针了。

7.malloc,calloc等函数的申请一定要进行free释放

8.free无法释放部分空间,申请多少空间就得释放多少空间

​
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	int* arr[10] = { 0 };
	int a = 1;
	int* add = (int*)malloc(10 * sizeof(int));
	if (add ==NULL)
	{
		perror("malloc");
}
	for (int i = 0; i < 10; i++)
	{
		*(add+i) = i+1;
		a++;
	}
	for (int i = 9;i >= 0; i--)
	{
		printf("%d\n", *(add + i));
	}
	free(add);//正确用法
	free(arr);//指向的空间不是动态开辟的,那free函数的行为是未定义的.
    add=NULL;//防止野指针被使用
	return 0;
}

​

malloc和free的还有一给好处就是可以手动选择变量的作用域,不用了就直接free.

2.calloc

calloc

void* calloc (size_t num, size_t size);

函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。

与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0.
 

malloc和calloc的区别主要在于以下几个方面:

函数原型和参数

malloc :  void *malloc(size_t size) 123
calloc :  void *calloc(size_t numElements, size_t sizeOfElement) 
参数差异 :
 malloc  只接受一个参数,即需要分配的内存空间的大小(以字节为单位)。
 calloc  需要两个参数,第一个参数是需要分配的元素的个数,第二个参数是每个元素的大小。

内存初始化

malloc : 分配的内存空间中的内容是随机的垃圾数据。
calloc : 分配的内存空间会被初始化为0。

返回值差异

malloc : 返回一个指向分配内存区域的指针,该区域的内容不可预知(通常包含垃圾数据)。
calloc : 返回一个指向分配内存区域第一个元素的指针,该区域的内容为0。

性能

calloc : 由于需要额外的初始化步骤,在分配大块内存时比 malloc 慢一些。
malloc : 适合用于一次性分配较小的内存块,而 calloc  更适合用于分配大量元素的数组,并且需要所有元素初始化为0。

3.realloc

realloc

void* realloc (void* ptr, size_t size);
realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的使用内存,我们一定会对内存的大小做灵活的调整。那realloc函数就可以做到对动态开辟内存大小的调整。
ptr是要调整的内存地址
size 调整之后新大小
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
realloc在调整内存空间的是存在两种情况:
情况1:原有空间之后有足够大的空间
情况2:原有空间之后没有足够大的空间

 情况1
当是情况1的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

也称原地扩容
情况2
当是情况2的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合大小的连续空间来使用。这样函数返回的是一个新的内存地址。

也称异地扩容

情况三:开辟失败,返回空指针

1.因为有上面三种情况所以我们在接受realloc的返回指针时,要用一共新的变量去接受,如果用malloc或者calloc的返回值接收会导致新的没开辟好,还把原来的那块空间搞丢了!

2.realloc只能作用于动态开辟的空间块,不是随便一块空间就行。

3.realloc并不会将初始化成0,和malloc一样是随机值。

4.如果realloc是异地扩容,realloc会将接手原来那块内存的释放,不需要你再进行free释放了,只用对realloc异地扩容的那段新内存进行free了,即对realloc的返回值进行free

5.realloc也可以开辟空间

int*ptr=(int*)reallloc(NULL,10*sizeof(int));

int*ptr=(int*)mallloc(10*sizeof(int));

是等价的

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	int*add = (int*)malloc(10 * sizeof(int));
	if (add==NULL)
	{
		perror("malloc");
	}
	int*sta = (int*)realloc(add, 20*sizeof(int));
	//先将realloc返回值放到sta中,不为NULL再放到add中
	if (sta!= NULL)
	{
		add= sta;
	}
	for (int i = 0; i < 20; i++)
	{
		{
			if (add != NULL)
			{
				*(add + i) = i + 1;
			}
		}
	}
	for (int i = 0; i < 20; i++)
	{
		{
			if (add!= NULL)
				printf("%d\n", *(add+ i));
		}
	}
	free(add);
	add = NULL;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值