总览
代码区
生成时间:编译之后
存放内容:二进制化的代码(包括注释)
控制方:操作系统
权限:-r--r--r--【全用户只读】【只读的作用:防止误改】
权限表示法[1]:
全局区
生成时间:编译之后
存放内容:全局变量常量 / 静态变量 / 字符串常量
控制方:程序运行结束后由操作系统自动释放【不理解:如果全局区是编译之后运行之前就存在并且存放完毕的,那么为何要在运行结束后由系统收回?如果下次运行之前重新分配,为什么不设置为运行之前再分配,而要在第一次编译之后就分配?】
全局常量/局部常量 全局变量/局部变量
名字的作用域可以互相嵌套,允许内层的作用域中重新定义外层作用域的名字
显式访问
但是同时,内层作用域可以通过显式访问访问到全局作用域(其实是在全局区中寻找名字)
#include <iostream> #include <string> using namespace std; int a = 10; int main() { cout << a << endl; // 输出1:访问到全局变量 10 int a = 20;// 内层作用域的a覆盖了外层作用域的a cout << a << endl; // 输出2: 访问到局部变量 20 cout << ::a << endl;// 输出3: 可以通过这种方法显式的访问去全局变量 10 }
栈区(heap)
存放内容:函数参数、局部变量
控制方:编译器自动分配收回【函数执行时分配,函数结束时收回,因此返回局部变量的地址是没有意义的】
#include <iostream>
#include <string>
using namespace std;
int* func()
{
int a = 10;
return &a;
}
int main()
{
int* p = func();
for (int i = 0;i < 10;i++)
{
cout << *p << endl;
}
return 0;
}
按照理解,应该尽量不要返回局部变量的地址,因为会在函数结束的时候做释放【到底什么叫释放】
实际上在测试的时候,如上代码每次返回的都是10,在新版中,编译器做无限次保留?可不可以理解为,变量a已经被释放了,但是当前地址没有赋予新的值,仍然保存之前放着的值,虽然是非法操作,但是暂时没有引起问题?
堆区(stack)
控制方:原则上程序员来分配和释放,系统会做保底释放;
new & delete 关键字[2]
new语法: 数据类型A指针 数据名 new 数据类型A【因为new命令返回的是地址】
delete语法 : delete 指向堆区的指针变量
#include <iostream>
#include <string>
using namespace std;
int main()
{
int* p = new int;//会在堆区为指针p开辟一个sizeof(int)的空间,并将该空间地址赋给p
cout << *p << endl;//由于未初始化,值是随机的
int* p2 = new int(10);//也可以初始化
cout << *p2 << endl;//输出为10
int* pn = new int[100];
pn[0] = 20; // 正确
//pn[100] = 30; // 错误越界
delete p;
delete p;//错误,p已经取消了和堆区的关联
int a = 10;
int* p3 = &a;
delete p3;//错误,不能delete指向栈区的指针
}
参考资料:
01 程序的内存模型-内存四区-代码区._哔哩哔哩_bilibili
02 程序的内存模型-内存四区-全局区_哔哩哔哩_bilibili
03 程序的内存模型-内存四区-栈区_哔哩哔哩_bilibili
04 程序的内存模型-内存四区-堆区_哔哩哔哩_bilibili
05 程序的内存模型-new运算符_哔哩哔哩_bilibili