说明:
我们的代码并非放在代码段里的,而是以文件的形式存在磁盘上的。
代码经过编译链接形成的二进制指令,才是放进代码段里的。(即可执行代码)
练习:
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";
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.代码段(常量区)
globalVar在哪里?
staticGlobalVar在哪里?
staticVar在哪里?
localVar在哪里?
num1 在哪里?
char2在哪里?
*char2在哪里?
pChar3在哪里?
*pChar3在哪里?
ptr1在哪里?
*ptr1在哪里?
答案:
CCCAA
AAADAB
解释这里的易错题:*pchar3在哪里?
char2和pchar3都是局部变量,放在栈区,这个好理解。"abcd"本身是常量字符串,无论其有没有被const修饰。
char2[]是一个数组,编译器将"abcd"拷至这个数组里,所以说,char2[]里的abcd是可修改的,是随着char2数组一起放在栈区的。
而pchar3指向的是原本的abcd,即放在代码区的常量字符串。所以,*pchar3是位于代码区的。
C++在原有基础上(malloc之流) 引入了new和delete。
new的用法:
//动态申请一个int类型的空间
int*p1 = new int;
//动态申请一个int类型的空间,并初始化为10
int*p2 = new int(10);
//动态申请10个int类型的空间
int*p3 = new int[10];
//动态申请10个int类型的空间,并将前三个分别初始化为1、2、3
int*p = new int[5]{1,2,3}; //注意:这种方式C++98是不支持的,C++11支持
delete的用法:
delete p1;
delete p2;
delete[] p3;
//注:下面这种写法是错误的
delete p1,p2; //这样写仅能delete p1
delete是一个操作符,后面直接跟操作数,不需要像free那样接 ( )。
之前C语言中学到的malloc、calloc、free等,C++中照样是可以用的。
❓那么问题来了:new/delete 和 malloc/free 的区别是什么?
区别一:在对待自定义类型上
其实两者对待内置类型没有区别。
但是对于自定义类型,new /delete 除了开空间还会调用构造函数和析构函数。
可见,new/delete是为自定义类型准备的。
区别二:开辟失败时
malloc申请空间失败会返回NULL,所以需要进行检查
而new申请不需要做检查,因为申请失败它直接抛异常:
通过try-catch可以知道发生了什么异常:
结果:bad allocation
区别三:new/delete是关键字,而malloc/free是函数
1.new和delete、new[]和detele[]一定要配起来使用,否则可能出问题。
如果这样写:
A*p=new A[3]; delete p;虽然不会造成内存泄露,但程序可能会崩溃。
2.
A*p=new A[3]; //调用了3次A的构造函数
delete[] p; //调用了3次A的析构函数
我们看看调用过程:
class A
{
public:
A() {
cout << "A()" << endl;
}
~A() {
cout << "~A()" << endl;
}
};
int main()
{
A* p1 = new A; //new自定义类型
delete p1;
A* p2 = (A*)malloc(sizeof(A)); //malloc自定义类型
free(p2);
int* p3 = new int; //new内置类型
delete p3;
int* p4 = (int*)malloc(sizeof(int)); //malloc内置类型
free(p4);
return 0;
}
结果:
可见,只有new/delete在操作自定义类型时,会自动调用构造和析构函数。
new/delete的底层原理其实是 调用了函数operator new / operator delete来申请和释放空间。
注:这里不是运算符重载,函数名就是operator new。
️️我们来看一下函数operator new :
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0) //通过malloc申请
if (_callnewh(size) == 0)
{
// 当内存不够,申请失败时
// 这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
可见,operator new 实际也是通过malloc来申请空间,而operator delete是通过free来释放空间的。
既然本质还是用malloc,那兜这么一圈的意义何在?
开空间的同时封装了malloc,失败时能符合C++new的失败机制,即抛异常。
Q: malloc/free和new/delete的区别 ?
从本质上:1.new/delete是关键字,而malloc/free是函数。
从功能上:
2.malloc/free仅能开空间,而new/delete在开空间的基础上还能自动调用构造/析构函数。
3.malloc开空间时要算好具体开的字节数,而new不用,想开几个,[ ]中指定对象个数即可。
4.malloc的返回值为void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型。
5.malloc申请空间失败时,返回的是NULL,因此使用时必须判空;new不需要,但是new需要捕获异常。