C语言中的动态内存分配函数

为什么需要动态内存分配

大多数的时候我们使用的内存空间开辟方式有:

int i = 5; //在栈空间开辟4字节,将5存放在这块内存空间
char arr[10] = { 0 }; //在栈上连续开辟10字节

在我们最开始声明一个数组时,必须要使用一个常量来指定数组的长度。但是在没有真正使用这个数组的时候,并不知道具体要开辟多大的内存空间,它所需要的空间取决于输入的数据。假设在一个程序中实际上我们只需要10字节,而声明的时候仅仅指定了4字节的空间,就会出现空间不足或者溢出;如果指定了10000字节或者更大的空间则会形成浪费。此时就可以使用动态内存分配了。
在这里插入图片描述

动态内存函数介绍

malloc、free

C语言为动态内存的分配提供了两个函数malloc和free,分别用于动态内存的分配和释放。

//malloc函数原型
void* malloc(size_t sz);

作用:开辟出 sz 字节的内存空间
所需头文件:stdlib.h 和 malloc.h

malloc
参数:所需开辟内存的大小,单位为字节
返回值:如果开辟成功了,则返回指向成功开辟的内存首地址的指针。否则返回空指针

malloc函数在开辟空间的时候是不对其赋值的,所以在使用之前赋值是很重要的!它开辟的是一块连续的内存空间,不会分开去开辟。另外还有一些编译器,在你使用malloc函数申请内存的时候,实际分配的又可能会比我们请求的要多一些。最后需要避免一个误区,在使用malloc开辟的内存之前,需要判断是否开辟成功,也就是判断返回的是不是空指针,因为我们不能对空指针进行解引用。
总结一下:

  • 开辟成功,返回一个指向开辟好的空间的指针。
  • 如果开辟失败,返回空指针
  • 返回值的类型为void*,malloc函数不知道开辟空间的类型,具体的类型有环境决定
  • malloc开辟空间时不对其初始化,使用前要赋值
  • 使用前判断是否为空指针,不能对空指针解引用操作
  • 如果机器要求边界对齐,返回的内存的起始地址要满足边界对齐的要求
//free函数原型
void free(void* ptr);

作用:释放动态内存
所需头文件:stdlib.h 和 malloc.h

free
参数:指向以前使用malloc、calloc或realloc分配的内存块的指针。
返回值:无

使用malloc函数开辟的内存之后,需要对这块内存进行回收。

  • free参数ptr指向的空间必须时动态开辟出来的
  • 参数ptr 如果是空指针,则函数什么事都不做
  • 使用free函数释放空间后,需要置成空指针

例如:

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

int main(void)
{
	int* p = NULL;
	p = (int*)malloc(20); //malloc返回的是void*,需要强转成需要的类型
	//使用
	if (p == NULL)
	{
		printf("开辟失败");
	}
	else
	{
		for (int i = 0; i < 10; i++)
		{

			*(p+i) = i; 
		}
	}
	//使用完之后需要释放
	free(p);
	p = NULL; //释放了并不代表不在,置成空指针,防止变成野指针
	return 0;
}

calloc、realloc

C语言中还提供了calloc 和 realloc函数来进行动态内存分配

//calloc函数原型
void* calloc(size_t num, size_t size);

作用:为num个大小为size的元素开辟一块内存空间,并且把内存空间的每个字节初始化为0,size_t是无符号整型。

所需头文件:stdlib.h

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

int main(void)
{
	int* p = NULL;
	p = calloc(10, sizeof(int)); //为10个int字节大小的元素分配内存空间
	if (p == NULL)
	{
		printf("开辟失败\n");
	}
	else
	{
		//使用
		for (int i = 0; i < 10; i++)
		{
			//将内存空间的每一个字节都初始化为0,所以会打印10个0
			printf("%d ", *(p + i));
		}

	}
	free(p);
	p = NULL;
	return 0;
}

所以当我们在动态内存开辟时,如果不需要初始化则使用malloc,如果想要开辟出的内存空间的每一个字节都初始化为0时,则使用calloc.
relloc

//realloc函数原型
void* realloc(void* ptr, size_t size);

作用:为之前动态申请的ptr所指向的内存空间,重新调整至sz个字节,并返回调整之后的内存起始地址。size_t是无符号整型

所需头文件:stdlib.h
我们需要注意:
在这里插入图片描述
示范:


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

int main(void)
{
	int* p = NULL;
	p = (int*)malloc(10);
	if (p == NULL)
	{
		printf("内存开辟失败!\n");
		return 0;
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//将p所指向的内存空间大小,调整到30字节
	int* pf = (int*)realloc(p, 30);
	if (pf != NULL)
	{
		for (int i = 10; i < 20; i++)
		{
			*(pf + i) = i;
			printf("%d ", *(pf + i));
		}
	}
	//释放
	free(pf);
	pf = NULL;
	return 0;
}

常见的动态内存错误

在使用动态内存分配时,经常出现很多的小错误。

对NULL指针进行解引用

动态内存分配最常见的错误就是没有检查所请求的内存空间是否分配成功,对于这些动态内存分配函数,当开辟失败时,它们都会返回一个空指针。我们是不能对没有初始化的指针和空指针进行解引用操作的!

对动态开辟的内存越界访问

这个错误就是在我们操作内存时超出了分配内存的边界

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

使用完动态开辟的内存后忘记释放

当我们在一个程序中使用完动态分配的内存后,一定要记得释放和回收,这样它才能被重新分配。如果使用完之后不进行释放,它既不使用,也不让别人使用。那么这块内存空间就像屁一样的存在,一点用都没有,相当于泄露了一样。因此这种情况被称为内存泄漏

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小酥诶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值