所属专栏:C“嘎嘎" 系统学习❤️
>博主首页:初阳785❤️
>代码托管:chuyang785❤️
>感谢大家的支持,您的点赞和关注是对我最大的支持!!!❤️
>博主也会更加的努力,创作出更优质的博文!!❤️
在学习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);
}
选择题:
选项 : A.栈 ;B.堆 ;C.数据段(静态区) ;D.代码段(常量区)
1.globalVar在哪里?____ ;2.staticGlobalVar在哪里?____;
3.staticVar在哪里?____ ;4.localVar在哪里?____;
5.num1 在哪里?____;
6.char2在哪里?____ ;7.* char2在哪里?___;
8.pChar3在哪里?____ ;9.* pChar3在哪里?____;
10.ptr1在哪里?____ ;11.* ptr1在哪里?____;
填空题:
1.sizeof(num1) = ____;
2.sizeof(char2) = ____;3. strlen(char2) = ____;
4.sizeof(pChar3) = ____; 5.strlen(pChar3) = ____;
6.sizeof(ptr1) = ____;
正确答案:
一:1-5:CCCAA,6-11:AAADAB
二:40,5,4,4/8,4,4/8
第一题的前5个因该都没什么问题,问题可能出现在6-11题,我们讲解一下;
在学习C语言的时候我们有讲到过动态内存够管理部分C语言当中的动态内存管理在这一篇文章中我们也有详细了解到什么是动态内存,为什么要存在动态内存,如果有对知识点模糊不清的可以回顾一下。
使用语法:
new + 类型(初始值)
delete + 类型
new + 类型[大小]
delete[] + 类型
int main()
{
//开辟一个int类型的空间
int* ptr1 = new int;
//开辟一个int类型的空间并初始化为2
int* ptr2 = new int(2);
delete ptr1;
delete ptr2;
//开辟一个int类型的数组,大小为3
int* ptr3 = new int[3];
//开辟一个int类型的数组,大小为10,并初始化
int* ptr4 = new int[10]{1,2,3,4};//没有被初始化的编译器会默认初始化为0
delete[] ptr3;
delete[] ptr4;
return 0;
}
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用
new[]和delete[],注意:匹配起来使用。
class text
{
public:
text(int val)
:_a(val)
{
}
private:
int _a;
};
int main()
{
//C语言中的malloc
text* t1 = (text*)malloc(sizeof(text));
//C++中的new
text* t2 = new text(1);
free(t1);
delete t2;
return 0;
}
从上面malloc和new出来用法不一样之外没什么区别,唯一的区别就是malloc无法对自定义类型进行初始化,而new可以对自定义类型进行初始化,也就是说new做了两件事:开辟空间+构造函数。delete也做了两件事情:调用析构函数+释放空间。
class stack
{
public:
stack(int capacity = 4)
{
cout << "stack()" << endl;
_a = new int[capacity];
_size = 0;
_capacity = capacity;
}
~stack()
{
cout << "~stack()" << endl;
delete[] _a;
_a = nullptr;
_size = 0;
_capacity = 0;
}
private:
int* _a;
int _size;
int _capacity;
};
int main()
{
stack* p1 = new stack(4);
delete p1;
return 0;
}
内存泄漏。
全局函数
,new在底层调用operator new全局函数来申请空间,delete在底层通过不是重载 底层其实是封装了malloc和free。
而且new在申 请空间失败时会抛异常,malloc会返回NULL。
官方库给定的封装:
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void* p;
while ((p = malloc(size)) == 0) //最要注意的是这里,malloc开辟失败是返回0,而operate delete开辟失败不是返回0,而是抛异常。
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
/*
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);
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
我们也可以从汇编的角度来看一看:
class text
{
public:
text(int a = 0)
{
_a = a;
cout << "text()" << endl;
}
~text()
{
cout << "~text()" << endl;
}
private:
int _a;
};
int main()
{
text* p1 = new text;
delete p1;
text* p2 = (text*)operator new(sizeof(text));
operator delete(p2);
return 0;
}
开空间+调用构造
,delete会调用析构+释放空间。
我们也可以这样理解:
new = operator new + 构造函数
delete = 析构函数 + operator delete
class text
{
public:
text(int a = 0)
{
_a = a;
cout << "text()" << endl;
}
~text()
{
cout << "~text()" << endl;
}
private:
int _a;
};
int main()
{
text* p1 = new text[10];
delete[] p1;
return 0;
而我们知道free是不能释放部分内存的
,所以程序会崩。new和delete匹配。
new[] 和delete[]匹配。
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表。
问一个问题,构造函数能显示调用吗?
答案是不能显示调用的,构造函数是创建对象时自动调用的。
但是析构函数可以显示调用。
所以C++中可以用定位new来显示调用构造函数
class text
{
public:
text(int a = 0)
{
_a = a;
cout << "text()" << endl;
}
~text()
{
cout << "~text()" << endl;
}
private:
int _a;
};
int main()
{
text* p1 =(text*)operator new(sizeof(text));
new(p1)text(1);
//上面两个加起来就等于text* p1 = new text;
p1->~text();
operator delete(p1);
//上面两个加起来就等于delete p1;
delete[] p1;
return 0;
}