malloc&calloc &realloc函数动态内存管理

广而告知: 博客写得好,Emoji要选好!!🎵 🎶 🔈 🔇 🔉 🔊 🔔 🔕 📣 📢
写博客是知识是巩固和温习,所以在这个信息爆炸的时代,每个人每天都要接收很多讯息,你的记忆是有限的,知识也是有限的,时间也是有限的,既然如此,那是时候磨亮我的五十米大刀了。 你很强,上天揽月你不行,你很强,下海捞鱼总行吧!

💀☠💩🤡👹👺👻👽👾🤖 -->渴望知识!!!

目录

1.malloc是用来开辟内存的。

1.1 mallc的特点

1.2 malloc开辟一个指向int 类型的空间

2 malloc是不是可以无限开辟?

3.内存区域:

4.malloc开辟内存空间的释放

5.局部变量的拓展

6.接下来我们看一下calloc函数

6.1calloc的原型是void *calloc(size_t num,size_t size)

6.2 calloc 特点

6.3 calloc 的释放

7.realloc 函数

7.1 realloc 函数原型

7.2 优点:

7.3内存空间的调整有3种情况:

7.4 程序实现扩容多20byte,用于存储增加的5个元素。

7.5 realloc函数可以当作malloc函数使用


1.malloc是用来开辟内存的。

1.1 mallc的特点

1)开辟的内存是连续的空间。 

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

3)如果开辟失败,则返回一个NULL指针。(NULL的头文件是<stdlib.h>)

4)malloc返回的类型是void *,所以malloc函数并不知道开辟的空间是什么类型,需要程序员在使用的时候进行定义。

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

1.2 malloc开辟一个指向int 类型的空间

并将int *p指向这个空间的首地址,

malloc(10*sizeof(int));  申请10个连续的内存空间用来存储int型。而指针p则是指向改空间的起始地址。 

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		perror("malloc");//开辟内存失败
		return 1; //程序开辟异常,结束返回1
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
		printf("%d ", *(p + i));
	}
	return 0;  //程序正常执行,结束然后0

}

2 malloc是不是可以无限开辟?

如果我们使用INT_MAX是不是可以重复开辟

那我们先查看一下INT_MAX=2,147,483,647,那对应地址是32-1=31位

当我们径INT_MAX*4的空间大小,让malloc去分配的时候,我们会发现:

执行perror("malloc");这段代码,并且打印malloc:not enough space。

从这里,我们也可以看的出来,开辟空间并不是可以无限开辟的。

#include <stdio.h>
#include <stdlib.h>

int main()
{
	int* p = (int*)malloc(INT_MAX*4); 
	if (p == NULL)
	{
		perror("malloc");
		return 1;  //异常返回
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
		printf("%d ", *(p + i));
	}
	return 0;

}

3.内存区域:

1)栈区

2)堆区

3)静态区

栈区:存放的是局部变量,或是形式参数,或是临时变量。

堆区:一般是用于动态内存分配,如malloc,calloc,realloc,free。

静态区:一般是存储是全局变量,或静态变量。 

4.malloc开辟内存空间的释放

开辟空间的位置:malloc函数 在堆区上申请内存空间
malloc内存的释放有两种方式
1)如果需要释放空间,需要使用free函数

如果使用free函数,只需要将p的起始地址传递给free函数就可以free(p)
2)如果没有使用free释放,在程序退出的时候,也会由操作系统来回收。 

断点在83行未指向free(p),我们可以看到指针未释放的地址。

断点执行完83行的free(p),执行到84行,我们发现虽然执行了free(p)释放之后,但是指针p还指向了该地址。

而此刻,因为操作系统已经对内存进行释放,因此此时的p就是一个野指针。

既然是野指针,那这个p就会容易造成不可预估的故障。

因此,我们需要在释放内存空间之后,给p=NULL;赋值一个空值。 

p=NULL;对释放后的指针赋予空值。

5.局部变量的拓展

int main()

{

int int i=10;

return 0;

}

i 局部变量,主函数调用完之后,这些局部变量就被回收,也就是创建和销毁的过程。 

进作用域的时候开始生命周期,出作用域的时候结束生命周期。 

6.接下来我们看一下calloc函数

同样,我们还是来到网站,然后我们找到stdlib.h这个头文件里面的calloc

https://cplusplus.com/reference/

6.1calloc的原型是void *calloc(size_t num,size_t size)

开辟一个数组,数组的大小是num个元素,一个元素的大小是size个字节大小的长度。

假设申请10个存放int型的空间,那就是(10,int),一个整型是4个字节,也就是10*4=40个字节内存空间。

6.2 calloc 特点

calloc 申请的空间默认初始化为0,把空间的所有的字节初始化为0,并返回起始地址给到指针p

malloc 申请的空间不会初始化,并返回起始地址给到指针p

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));   //用一个整型指针来维护,因此也需要对calloc进行强制类型转换
	if (p == NULL)
	{
		perror("calloc");
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}

6.3 calloc 的释放

使用free(p)函数进行内存释放。 

7.realloc 函数

7.1 realloc 函数原型

void *realloc(void*ptr,size_T size);

ptr 要调整的内存地址

size 调整后的内存空间大小

7.2 优点:

可以对空间大小进行调整,可以对动态内存进行管理更加的灵活。 内存空间可以增加或者减小。 

7.3内存空间的调整有3种情况:

情况1:在原有内存空间的后面空间足够,调整内存空间,直接在其后面增加,并返回原有的地址给到指针p

情况2:在原有内存空间的后面空间不够,调整内存空间,将会在其他堆上找到一块足够存放扩容之后的会将原来内存空间的元素复制到新的空间,并将原来旧的空间销毁掉。 

然后返回新的地址给到p

情况3:如果扩容失败,则会返回NULL空指针。

在这里,我们要注意一下,如果原有空间指向的指针的p来维护。 

那么扩容之后返回的地址需要重新定义一个指针变量ptr用来维护这个扩容之后的内存地址。

然后如果扩容成功,则将p指向ptr,也就是p=ptr。

7.4 程序实现扩容多20byte,用于存储增加的5个元素。

由于扩容的元素类型是int型,一个元素占用4个byte,5个元素就是20byte。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(5 * sizeof(int));   //向内存申请了5个空间,起始地址返回来给到p,整型指针解引用就是第一个元素,+1就是跳过一个元素
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}

	for (int i = 0; i < 5; i++)
	{
		*(p + i) = i + 1;
		printf("%d ", *(p + i));
	}
	printf("\n");
	//调整申请堆上的内存,可以增加或者减少
	int *ptr=(int *)realloc(p, 40); //realloc 的p是调整p的内存地址,而40则是调整的内存空间大小,40个字节。 
	
	if (ptr != NULL)
	{
		p = ptr;
		ptr = NULL; //这里可以把ptr赋值成空指针,但是不能free(ptr),如果free掉ptr之后,p也会被free掉。
	}
	else
	{
		perror("realloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p);
	p = NULL;

	return 0;
}

0

可以看得出来,前面5个字节是我们对p指向的前5个元素进行了赋值,而后面5个元素是没有赋值的,所以出现的值是随机值。 

7.5 realloc函数可以当作malloc函数使用

当realloc 函数的第一个元素为空指针的时候,它的作用相当于malloc函数,可以用来开辟内存空间,并返回首地址。 


#include <stdio.h>
#include <stdio.h>
int main()
{
	int* p = (int*)realloc(NULL, 40);   //因为第一个元素是空指针,因此它的作用类似于malloc函数。 
	if (p == NULL)
	{
		perror("realloc");
		return 1;
	}
	return 0;

最后,请各位发财的金手指,帮忙点点赞和关注!

💁‍♂️💁‍♀️🙋🙋‍♂️🙋‍♀️🧏🧏‍♂️一赞三连🧏‍♀️🙇🙇‍♂️🙇‍♀️🤦🤦‍♂️🤦‍♀️🤷🤷‍♂️🤷‍♀️

💁‍♂️💁‍♀️🙋🙋‍♂️🙋‍♀️🧏🧏‍♂️一赞三连🧏‍♀️🙇🙇‍♂️🙇‍♀️🤦🤦‍♂️🤦‍♀️🤷🤷‍♂️🤷‍♀️

💁‍♂️💁‍♀️🙋🙋‍♂️🙋‍♀️🧏🧏‍♂️一赞三连🧏‍♀️🙇🙇‍♂️🙇‍♀️🤦🤦‍♂️🤦‍♀️🤷🤷‍♂️🤷‍♀️
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值