C/C++:动态内存管理详解戳这里

17 篇文章 1 订阅

C/C++程序的内存开辟
在这里插入图片描述
分配方式
1.从静态存储区域分配。内存在程序编译的时候就已经分配好,在程序整个运行期间都存在,例如:全局变量、static变量。静态分配区域的生命周期是代码的整个运行期,当代码终止运行后,这块内存才会被系统回收。
2.在栈上创建。在执行函数时,函数内局部变量的存储单元可以在栈上开辟创建,但在函数执行过程中会被自动释放。如果是在函数中定义的局部变量,则生命周期就是函数被调用的过程。
3.在堆中进行分配。也称为动态内存分配(由程序员进行申请和释放)

动态内存分配

我们曾经学习过两种动态内存的开辟方式:

int  value = 20;//在栈空间中开辟了四个字节
char arr[10] = {0};//在栈空间上开辟了10个字节的连续空间

上面的开辟空间方式有两种:

  1. 开辟固定大小的空间
  2. 数组在声明的时候,必须指定数组的长度,数组是在栈上开辟空间,它所需要的内存在编译时自动分配(数组不能定义未知的一个变量)

但对于空间的需求,有时候我们需要的空间大小在程序运行时才知道,但数组的编译时开辟空间的方式就不能满足了,此时就需要动态内存开辟。

动态内存函数的介绍

malloc和free

C语言提供了一个动态内存开辟的函数:

void* malloc(size_t size);

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针;
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
  • 如果参数size为0,malloc的行为是标准未定义的,取决于编译器

C语言提供了一个另外一个函数free,专门用来做动态内存的释放和回收的,函数的声明如下:

viod free(void* ptr);

free函数用来释放动态开辟的内存

  • 如果参数ptr指向的空间不是动态开辟的,free函数的行为是未定义的
  • 如果参数ptr是NULL指针,则函数不需要执行操作

说明:
1.free和malloc缺一不可,他们成对出现;
2.malloc函数在使用时,如果不使用free释放,,就会出现内存泄露的情况
3.当实际情况远远大于期望设置空间,free函数并没有告知要释放多少字节的信息;
4.free传进来的是起始地址,但未设置要释放多少,而释放前后的地址没有变,释放后指针和内存关系是没有关联的;
5.free不需要清空它的内存空间(这样是为了提高计算机的效率);
6.free没有告知要释放多少空间,但malloc会保存要释放多少字节的信息;
7.malloc和free 函数声明都包括在stdlib.h头文件中
8.在代码编写过程中,要注意将指针设置为空,以免出现非法指向变成野指针;

申请动态内存:

//申请动态内存
	int  n = 30;
	char *name = (char*)malloc(n);
	if (name == NULL){
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (; i < n; i++){
		name[i] = i;
	}
	free(name);
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#pragma warning(disable:4996)
int main()
{
    int num = 0;
    scanf("%d", &num);
    int arr[num] = { 0 };
	int* ptr = NULL;
	ptr = (int*)malloc(num*sizeof(int));
	if (NULL != ptr)//判断ptr指针是否为空
	{
		int i = 0;
		for (i = 0; i < num; i++){
			*(ptr + i) = 0;
		}
	}
	free(ptr);//释放ptr指针所指向的动态内存
	ptr = NULL;//将指针设置为空
	system("pause");
	return 0;
}

calloc函数

函数原型

void* calloc(size_t num, size_t size)

  • 函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0;
  • 与函数malloc的区别是calloc会在返回地址之前把申请的空间的每个字节都初始化为全0;

realloc函数

  • realloc函数对动态内存的管理更加灵活
  • 当我们在申请空间后,觉得大下不合适时,为了合理申请内存,我们可以使用realloc函数对动态开辟内存的大小进行灵活的调整

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

  • ptr是需要调整的内存地址(返回值)
  • size 是调整之后的新大小
  • 返回值为调整之后的内存起始位置
  • 函数在调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间
  • realloc函数在调整内存空间存在两种情况:
    1.原有的空间之后有足够大的空间,当需要扩展内存时,直接在原有内存之后追加,原来空间的数据不会发生变化;
    2.原有空间后没有足够大的空间,扩展方法是在堆空间上另找一个合适大小的连续空间使用,这样返回的是一个新内存的地址。

以上三个函数都是C语言中用来进行动态内存申请的库函数,申请的空间都在堆上,用完之后必须使用free函数进行释放。

void Test()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);
	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int)*10);
	free(p2);
	free(p3);
}

常见动态内存错误:

  • 对NULL进行解引用
  • 对动态开辟的内存进行越界访问
  • 对非动态开辟的内存进行free
  • free动态内存的一部分,而不是全部释放
  • 对同一块内存释放多次次
  • 忘记free,造成内存泄露

我们在编写程序时,要避免这些错误的出现。

C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但在有些地方使用起来就变得非常麻烦,因此C++提出了自己的内存管理方式,通过newdelete操作符进行动态内存管理。new和delete会自动调用默认成员函数,new 时调用构造函数,delete时调用析构函数。

new和delete 动态管理对象
new[ ]和delete[ ] 动态管理对象数组

其中delete释放new分配的单个对象指针指向的内存;
delete[ ]释放new[ ]分配的单个对象数组指针指向的内存;

void Test()
{
	//动态申请一个int类型的空间
	int* ptr1 = new int;

	//动态申请一个int类型的空间并初始化为20
	int* ptr2 = new int(20);
	
	//动态申请10个int类型的空间
	int* ptr3 = new int[10];
	
	delete ptr1;
	delete ptr2;
	delete[] ptr3;
}

new/delete和malloc/free区别和联系
联系:
它们都是动态内存管理的入口,new的本质还是调用了malloc函数。

区别

  • new/delete是关键字,malloc/free是库函数;
  • new操作符在自由存储区分配空间,不一定是堆上(还有可能是静态存储区),取决于operator new的实现细节,new甚至可以部位对象分配空间,但malloc申请必须是堆上;
  • 对数组进行处理时,C++中new[ ]/delete[ ]专门进行处理,而malloc对此无区分度;
  • new可以调用malloc,但是malloc不可以调用new;
  • malloc/free只是动态分配空间,释放空间,而new/delete除了分配空间,还会调用构造函数和析构函数进行初始化和释放空间;
  • malloc/free需要手动计算类型大小并返回void*,new/delete自动计算大小,返回对应指针;
  • malloc申请失败会返回空指针,而new/delete失败会抛出异常并用try/catch捕捉异常;
  • malloc可以直观重新分配内存,当内存不够时,可以调用realloc来申请空间。将数据拷贝过去并释放原来的空间,而new没有这样的机制。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值