内容纲要
内存分区模型:laughing:
C++ 程序再执行时,将内存大方向划分为4 个区域
- 代码区:存放函数体的二进制代码,由操作系统进行管理
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,则程序结束时由操作系统回收
内存四区的意义:
不同的区域存放的数据,赋予不同的生命周期,使编程更灵活
程序运行前
在程序编译后,生成exe 可执行程序,未执行该程序前分为两个区域
代码区:
- 存放 CPU 执行的机器指令
- 代码区是 共享 的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。(比如说你同时打开同一个程序两次,登录2个QQ)
- 代码区是 只读 的,使其只读的原因是防止程序意外的修改了它的指令。
全局区:
- 全局变量 和静态变量 存放于此。
- 全局区还包含了 常量区,字符串常量 和其它常量 也存放于此。
- 该区域的数据在程序结束后由操作系统释放。:confused:
- 示例代码
#include <iostream>
#include "string"
using namespace std;
int global_a = 10; //全局变量
int global_b = 10;
const int c_global_a = 10;
const int c_global_b = 10;
//int s_global_a = 20;
void main1() {
//全局区
//全局变量、静态变量、常量
//创建普通局部变量
int a = 10; //局部变量
int b = 10;
cout << "局部变量a 的地址为:" << (int)&a << endl;
cout << "局部变量b 的地址为:" << (int)&b << endl;
cout << "全局变量a 的地址为:" << (int)&global_a << endl;
cout << "全局变量b 的地址为:" << (int)&global_b << endl;
//静态变量 在普通变量前面加static ,属于静态变量
static int s_global_a = 10;
static int s_global_b = 10;
//静态变量和局部变量不能冲突。但是在全局变量中定义和静态变量同名时,编译器不报错,可以运行。。
//虽然不报错,但是如果调用同名的变量,它会调用为静态变量中的值。
cout << "静态变量a 的地址为:" << (int)&s_global_a << endl;
//cout << "s_global_a的值为: " << s_global_a << endl; //10
cout << "静态变量b 的地址为:" << (int)&s_global_b << endl;
//常量
//字符串常量
cout << "字符串常量的地址为:" << (int)&"hello" << endl; //常
//const 修饰的变量
//const 修饰的全局变量,const 修饰的局部变量、
cout << "全局常量 c_global_a 的地址为:" << (int)&c_global_a << endl;
cout << "全局常量 c_global_b 的地址为:" << (int)&c_global_b << endl;
int c_local_a = 10;
int c_local_b = 10;
cout << "局部常量 c_local_a 的地址为:" << (int)&c_local_a << endl;
cout << "局部常量 c_local_b 的地址为:" << (int)&c_local_b << endl;
}
void hello() {
//cout << (int)&a;
}
结论:
- C++中在程序运行前分为 全局区 和 代码区
- 代码区的特点是共享和只读
- 全局区中存放全局变量、静态变量、常量
- 常量区中存放 const修饰的全局常量 和 字符串常量
程序运行后
栈区:
- 由编译器自动分配释放,存放函数的参数值,局部变量等。
2.注意事项:不要返回局部变量的地址!!!!栈区开辟的数据由编译器自动释放
#include <iostream>
using namespace std;
int* func(int b) //形参数据也会存在于栈区
{
b = 100;
int a = b; //局部变量,存放在栈中,生命周期随着函数的结束而销毁。
return &b; //返回局部变量的地址
}
void main() {
int* p = func(10);
//第一次可以打印正确的数字,因为编译器做了保留,怕程序员误操作
cout << "栈返回的地址打印解指针: " << *p << endl;
//第二次数据就不再保留了。
cout << "栈返回的地址打印解指针: " << *p << endl;
system("pause");
}
堆区:
- 由程序员分配释放,若程序员不释放,程序结束时由操作系统回收。
- 在C++ 中主要利用new 在堆开辟内存。
//利用new 关键字, 可以将数据开辟到堆区。
//指针 本质也是一个局部变量,存放于栈上,下方代码中 指针 保存的数据放在堆区!
#include<iostream>
using namespace std;
int * func()
{
int * a = new int(10);
return a;
}
void main()
{
//在堆区开辟数据。
int * p = func();
cout << "局部变量中用new 开辟的内存地址解指针: " << *p << endl;
cout << "局部变量中用new 开辟的内存地址解指针: " << *p << endl;
cout << "局部变量中用new 开辟的内存地址解指针: " << *p << endl;
system("pause");
}
new操作符
- C++ 中利用new 操作符在堆区开辟数据
- 堆区开辟的数据,由程序员手动开辟,手动释放,释放操作符用
delete
- 语法:
new 数据类型
- 利用new 创建的数据,会返回数据对应类型的指针
#include<iostream>
using namespace std;
//1、new的基本语法
double * func()
{
//在堆区创建整型数据
//new 返回是 该数据类型的指针。
double * a = new double(10.1);
return a;
}
int* test1()
{
//用new 在堆中创建数组
int* b = new int[10];
for (size_t i = 0; i < 10; i++)
{
b[i] = 100 + i;
}
for (size_t j = 0; j < 10; j++)
{
cout << b[j] << endl;
}
return b;
}
void printInfo() {
double* p = func();
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
delete p;
cout << *p << endl; //内存已经被释放,再次访问会非法操作报错。
}
void main()
{
//printInfo();
int *p = test1();
delete[] p;
}
- 注意删除数组的时候要用
delete[] p
- 要养成创建删除的好习惯,不然内存泄漏。。。