一、内存分区模型
概述:C++程序在执行时,将内存划分为4个区域
程序运行前:
代码区:存放函数体的二进制代码,由操作系统管理
①共享。共享的目的是对于频繁被执行的程序,在内存中只需有一份代码即可
②只读。使其只读,以防止程序意外修改其指令
全局区:存放全局变量、静态变量及常量
①存放全局变量和静态变量
②包含常量区,字符串常量与其他常量也在其中
③该区域的数据在程序结束后由操作系统释放
对于这些代码,运行后
可以发现全局变量和静态变量是在同一个区的
而对于常量以及const修饰的变量
执行后:
可以发现:
常量与const修饰的全局变量都在一个区里(即全局区)
而const修饰的局部变量和局部变量在一个区里
程序运行后:
栈区:存放函数的参数值、局部变量等,由编译器自由分配释放
注意:不要返回栈区局部变量的地址
例:
int* func() // 而如果有形参,则形参数据也存放在栈区
{
int a = 500; // 局部变量,存放在栈区,程序执行完后自动释放
return &a; // 返回局部变量的地址
}
int main()
{
int* p = func();
cout << *p << endl; // 当编译器做保留时,数据还能打印1次
cout << *p << endl; // 将是乱码,非法访问了
return 0;
}
ps:不过经我测试,在vs2022中,x64平台下栈区数据始终保留,无论打印多少次都行;而改到x86下,只能打印1次,第2次开始就是非法访问
堆区:由程序员自行分配与释放,若不进行释放则在程序结束时由操作系统回收
在c++中主要使用new在堆区开辟内存
int* func()
{
// new 类型(初识值);返回的是所开辟内存的地址
int* p = new int(10);
// 而指针p仍在栈上,不过其所保留的地址在堆上
return p;
}
int main()
{
int*p= func();
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
return 0;
}
无论执行多少次程序,结果总是10
意义:不同区域存放的数据有不同的生命周期,使编程更为灵活
new操作符
作用:在堆区开辟数据,返回对应类型的指针
对于堆区开辟的数据,程序员手动开辟,手动释放
释放使用操作符delete
new整型数据
int* func()
{
int* p = new int(120);
return p;
}
void test1()
{
int* p = func();
cout << *p;
delete p; // 释放p空间,不可再被使用
}
new一个数组
void test2()
{
int* parr = new int[10]; //new一个有10个数据的整型数组
for (int i = 0; i < 10; i++)
{
parr[i] = i + 10; // 赋值,从10-19
}
for (int i = 0; i < 10; i++)
{
cout << parr[i] << endl; // 打印
}
// 释放堆区数组 - 要加[]
delete[] parr;
}
释放一个数组的数据,要写delete[] arr;
delete后加个[]