动态内存管理(动态内存函数、常见动态内存错误)

动态内存管理在编程中至关重要,涉及malloc、calloc、realloc和free等函数。malloc用于按需分配内存,calloc一次性分配并初始化为0,realloc调整内存大小,free释放内存。程序员应注意检查NULL指针、防止内存越界、避免释放非动态内存、释放内存部分或重复释放等问题,防止内存泄漏和程序错误。
摘要由CSDN通过智能技术生成

动态内存管理

1.为什么要进行动态内存分配?

int a = 10;
char arr[20] = {0};

以上是我们所掌握的内存开辟方式,该种开辟方式具有以下特点:

  1. 空间开辟大小固定。
  2. 数组在声明时必须指定长度。

但对于空间的需求,有时所需空间的大小只有在程序运行时才知道,那上述数组的开辟空间方式就不能满足了。

这时候就需要进行动态内存开辟

2.动态内存函数

2.1 malloc

#include <stdlib.h>
void* malloc(size_t size);

该函数向内存申请了一块大小为size字节的连续可用的空间。

  • 若开辟成功,则返回新申请空间的指针

  • 若开辟失败,则返回空指针NULL

  • 返回值类型为void*,使用时需要使用者自行进行类型转换,例如:

    int main()
    {
        malloc(20);
        int* p = (int*)malloc(20);
        return 0;
    }
    

2.2 free

#include <stdlib.h>
void free(void* ptr);

该函数用来释放动态开辟的空间,例如:

int main()
{
    int* p = (int*)malloc(20);
	free(p);
	p = NULL;//释放完空间后,p仍指向原本空间,为保证安全,应主动将p置为空
    return 0;
}

2.3 calloc

#include <stdlib.h>
void* calloc(size_t num,size_t size)

该函数开辟num个以size为大小的空间,并将空间中每个字节初始化为0

malloc函数一样:

  • 若开辟成功,则返回新申请空间的指针

  • 若开辟失败,则返回空指针NULL

  • 返回值类型为void*使用时需要使用者自行进行类型转换

2.4realloc

void* realloc (void* ptr,size_t size);
  • ptr为要调整的内存地址
  • size为调整后的大小
  • 返回值为调整后的内存起始位置

该函数可以做到对动态开辟内存大小的调整,使动态内存管理更加灵活,例如:

int main()
{
    int* p = (int*)malloc(20);
	realloc(p,40);
	return 0;
}

但需要注意的是,realloc的调整内存空间有两种情况:

  1. 若原空间后足够大的内存空间,则会直接在原内存后拓展新的空间,原来空间的数据不会发生变化
  2. 若原空间后没有足够大的内存空间,则会在堆区另找合适的空间来使用,并将原空间的数据拷贝到新空间

3.常见的动态内存错误

结合上述各个动态内存函数特点,以下是我们在编写代码时可能会遇到的错误:

3.1对NULL指针的解引用

int main()
{
	int* p = (int*)malloc(20);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		p[i] = i;
	}
	free(p);
	p = NULL;
    
	return 0;
}
  • 上述代码中malloc函数可能申请空间失败,因此在使用p之前,需要先判断p是否为NULL

3.2对动态开辟空间进行越界访问

int main()
{
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("内存空间开辟失败\n");
		return 1;
	}
    
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p[i] = i;
	}
    
	free(p);
	p = NULL;
    
	return 0;
}
  • 上述代码只申请了20个字节的空间,却非法访问了4*10=40个字节的空间

3.3对非动态开辟的内存进行free释放

int main()
{
    int arr[10] = { 1,2,3,4,5 };
	int* p = arr;
	
	free(p);
	p = NULL;

	return 0;
}
  • 上述代码对非动态开辟的内存进行了free释放,程序会报错

3.4使用free释放一块动态开辟内存的一部分

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		printf("内存空间开辟失败\n");
		return 1;
	}

	int i = 0;
	//[1] [2] [3] [4] [5] [ ] [ ] [ ] [ ] [ ] 
	for (i = 0; i < 5; i++)
	{
		*p = i + 1;
		p++;
	}

	free(p);
	p = NULL;

	return 0;
}
  • 上述代码只free释放了p+4p+9的动态开辟内存空间,程序执行时仍会报错

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

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

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

	return 0;
}
  • 上述代码对同一块内存空间进行了多次释放,程序会报错

3.6动态开辟内存忘记释放(内存泄漏)

void test()
{
	int* p = (int*)malloc(20);
}
int main()
{
	test();

	return 0;
}
  • 上述代码在test函数内申请完内存空间没有进行free释放,该动态内存空间会一直存在于堆区,直至程序结束操作系统主动回收该块空间。虽然程序可以正常运行,但在程序结束前,该空间被浪费
    存空间进行了多次释放,程序会报错

3.6动态开辟内存忘记释放(内存泄漏)

void test()
{
	int* p = (int*)malloc(20);
}
int main()
{
	test();

	return 0;
}
  • 上述代码在test函数内申请完内存空间没有进行free释放,该动态内存空间会一直存在于堆区,直至程序结束操作系统主动回收该块空间。虽然程序可以正常运行,但在程序结束前,该空间被浪费
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值