【C++】C/C++内存管理

1. C/C++内存管理

我们先来看下面的一段代码和相关问题
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
 static int staticVar = 1;
 int localVar = 1;
 int num1[10] = { 1, 2, 3, 4 };
 char char2[] = "abcd";
 const char* pChar3 = "abcd";
 int* ptr1 = (int*)malloc(sizeof(int) * 4);
 int* ptr2 = (int*)calloc(4, sizeof(int));
 int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
 free(ptr1);
 free(ptr3);
}
1. 选择题:
  选项 : A .   B .   C . 数据段 ( 静态区 )   D . 代码段 ( 常量区 )
  globalVar 在哪里? ____   staticGlobalVar 在哪里? ____
  staticVar 在哪里? ____   localVar 在哪里? ____
  num1 在哪里? ____
  char2 在哪里? ____   * char2 在哪里? ___
  pChar3 在哪里? ____       * pChar3 在哪里? ____
  ptr1 在哪里? ____         * ptr1 在哪里? ____
2. 填空题:
  sizeof ( num1 ) = ____ ;
  sizeof ( char2 ) = ____ ;       strlen ( char2 ) = ____ ;
  sizeof ( pChar3 ) = ____ ;     strlen ( pChar3 ) = ____ ;
  sizeof ( ptr1 ) = ____ ;
3. sizeof strlen 区别?
1.sizeof()是运算符,strlen()是库函数
2.sizeof()在编译时计算好了,strlen()在运行时计算
3.sizeof()计算出对象使用的最大字节数,strlen()计算字符串的实际长度(不包含‘/0’)
4.sizeof()的参数类型多样化(数组,指针,对象,函数都可以),strlen()的参数必须是字符型指针
答案:1.DDDAA;AAADAB 2.40;5;4;4/8;4;4/8
【说明】
1. 又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。
2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)
3. 用于程序运行时动态内存分配,堆是可以上增长的。
4. 数据段--存储全局数据和静态数据。
5. 代码段--可执行的代码/只读常量。

[问题]malloc/calloc/realloc的区别

calloc-分配内存、把内存清零。

malloc-分配内存、不把内存清零。
realloc-重新分配内存,把之前的数据搬到新内存去。

realloc(NULL, size)等价于malloc(size)。
calloc(num, size)基本上等于void *p = malloc(num *size); memset(p, 0, num * size);但理论上calloc的实现可避免 num * size溢出,当溢出时返回NULL代表失败,而malloc(num * size)可能会分配了一个尺寸溢出后的内存。

2. new/delete使用方法

1.内置类型

#include <iostream>
using namespace std;

int main()
{
	int* p1 = new int;//在堆区申请一个int大小的空间,并未初始化
	int* p2 = new int(1);//在堆区申请一个int大小的空间,并初始化为0
	delete p1;//释放p1所指向的空间
	delete p2;

	int* p3 = new int[10];//在堆区申请一个10*int大小的空间,并未初始化
	int* p4 = new int[10]{1,2,3};//在堆区申请一个10*int大小的空间,并初始化为{1,2,3,0,0,0,0,0,0,0}
	delete[] p3;//释放p3所指向的空间,注意申请多个空间要加[]
	delete[] p4;

}

2.自定义类型

class Date
{
public:
	// 默认构造函数
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	// 开辟一个自定义类型的一个日期类大小的空间
	// 调用无参/全缺省构造函数
	Date* ptr1 = new Date;
	// 调用有参构造函数
	Date* ptr2 = new Date(2023, 8, 19);

	// 开辟一个自定义类型(日期类)的连续空间
	// 自动调用-默认构造函数-完成日期类的初始化操作
	// 如果没有默认构造函数,编译器报错
	Date* ptr3 = new Date[3];
	ptr1->Print();//调用Date类函数
	ptr2->Print();
	ptr3->Print();
	// 释放自定义类型的空间
	// 1.先调用析构函数清理资源
	// 2.再释放空间
	delete ptr1;	// 调用一次析构函数,再释放空间
	delete ptr2;	// 调用一次析构函数,再释放空间
	delete[] ptr3;	// 调用三次析构函数,再释放空间(仅一次)

	return 0;
	// 注意:在申请自定义类型的空间时
	// new会调用构造函数,delete会调用析构函数
	// 而malloc与free不会
}

3. new、delete和malloc、free的区别

1、对于内置类型,没有区别。

2、new和delete是C++的关键字/操作符,而malloc和free是C语言的库函数。

3、对于自定义类型,相比于malloc和free,new和delete会额外调用类中的构造函数和析构函数。

4、malloc的返回值是void*,使用时需要强转,new后边跟的是空间的类型,所以new不需要强转。

5、malloc失败返回空指针,需要判空;new失败抛异常,需要捕获异常。


4.new/delete的原理

1.new原理

new等于operator new()+构造函数。operator new()不是new运算符的重载,因为参数没有自定义类型。它是一个库里的全局函数。

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) 
{
// try to allocate size bytes
    void *p;
    while ((p = malloc(size)) == 0)
         if (_callnewh(size) == 0)
         {
             // report no memory
             // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
             static const std::bad_alloc nomem;
             _RAISE(nomem);
         }
    return (p);
}

从底层代码可以看出operator new()是对malloc的封装,如果malloc失败,将会抛出异常。

2.delete原理

delete等于operator delete()+析构函数

//operator delete: 该函数最终是通过free来释放空间的
void operator delete(void *pUserData) {
     _CrtMemBlockHeader * pHead;
     RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
     if (pUserData == NULL)
         return;
     _mlock(_HEAP_LOCK);  /* block other threads */
     __TRY
         /* get a pointer to memory block header */
         pHead = pHdr(pUserData);
          /* verify block type */
         _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
         _free_dbg( pUserData, pHead->nBlockUse );//调用free()
     __FINALLY
         _munlock(_HEAP_LOCK);  /* release other threads */
     __END_TRY_FINALLY
     return; }
//free的实现
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

.从底层代码可以看出operator delete()调用了free。

所以针对内置类型或无资源的类对象delete时,使用delete和free效果相同。但对于有资源需要释放的对象时,直接使用free虽然释放了对象的空间,但对象内部的资源还未被清理,导致内存泄漏!这种情况必须使用delete。
 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_hhc_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值