C++核心编程
进阶篇主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓。
内存分区模型(内存四区)
C++程序在执行时,将内存大方向划分为4个区域
- 代码区:存放函数体的二进制代码,由操作系统管理的
- 全局区:存放全局变量和静态变量以及常量
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
内存四区意义:
不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程

1. 程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
简述: 在程序编译后和运行程序前之间的阶段分为两个区域分别是代码区 和全局区
1.1 代码区
代码区:
- 存放CPU执行的机器指令
- 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
- 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
代码区共享: 代码区就是内存中存放exe可执行程序的机器指令,双击exe就会调用代码区存储的程序,再双击一次exe不会开辟新的存放代码的内存空间,而是继续调用已有的代码区,这个就是代码区的共享 ,因为代码区在运行程序(双击exe)之前就已经创建了,所以不管双击几次exe始终都是调用这一个代码区。

代码区只读: 假设我的代码里写的是游戏代码,现在只有十个银币,假设代码区没有只读限制,双击exe 以后变一百个银币了,然后再双击一次变一千个银币了,我运行一次程序就更改一次代码的机器指令那显然不正常吧,所以有了代码区只读限制。运行程序(双击exe)后只能读取代码不可以改变代码区中的代码这就是代码区只读。
1.2 全局区
全局区:
- 全局变量和静态变量存放在此
- 全局区还包含了常量区,字符串常量和其他常量也存放在此
- 该区域的数据在程序结束后由操作系统释放
注:const修饰的常量不能决定在全局区,局部变量修饰const常量还是存放在栈区。
static静态的:static是C / C++中的关键字,可以将局部变量修饰成静态变量,当我们使用static修饰局部变量后局部变量不再存储在栈区而是存储在静态区(全局区),生命周期也变为了整个程序。
static的第二种功能: 可以将外部链接属性 改为内部链接属性,当我们使用static修饰全局变量时,全局变量存储区域还是全局区,但是只是修改了全局变量的链接属性。
**外部链接属性:**所有文件都可以调用
**内部链接属性:**只有当前文件可以调用

总结:
- C++中在程序运行前分为全局区和代码区
- 代码区特点是共享和只读
- 全局区中存放全局变量、静态变量、常量
- 常量区中存放 const修饰的全局常量 和 字符串常量
2. 程序运行后
运行程序后才开辟的两个区,分别是栈区和堆区。
2.1 栈区
栈区:
- 由编译器自动分配释放,存放函数的参数值,局部变量等
- 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
示例:
cpp
#include<iostream>
using namespace std;
int* fun()
{
int a = 10;
return &a;
}
int main()
{
int* ret = fun();
cout << *ret << endl;//会报错
system("pause");
return 0;
}
因为局部变量在函数结束时会随着函数一起被编译器释放掉,那这块空间就是非法的,我们接收这块地址再解引用就会报错。
2.2 堆区
堆区:
- 由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
- 在C++中主要利用关键字new在堆区开辟内存
cpp
#include<iostream>
using namespace std;
int* fun()
{
int* a = new int(10);//new后面是需要开辟的数据类型括号里是这个类型的数值
//最后new会在堆区开辟一个4个字节的内存空间存储这个10并返回开辟好的地址给指针a
return a;
}
int main()
{
int* ret = fun();
cout << *ret << endl;//10
system("pause");
return 0;
}
**new:利用new关键字在堆区开辟一块空间并给一个初始值10,**new后面是需要开辟的数据类型括号里是这个类型的数值,最后new会在堆区开辟一个int类型的4个字节的内存空间存储这个数据10并返回开辟好的空间的地址给指针a
总结:
堆区数据由程序员管理开辟和释放
堆区数据利用new关键字进行开辟内存
2.3 new操作符
C++中利用new操作符在堆区开辟数据
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete
语法: new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针
new的基本语法:
2.3.1 new开辟空间
两种语句形式:
cpp
//两种形式
//1.开辟int大小内存时放入数据10并返回空间地址
int* a = new int(10);
//2.只开辟一块int大小内存并返回空间地址
int* b = new int;
*b = 10;
示例:
cpp
#include<iostream>
using namespace std;
int* fun()
{
int* a = new int(10);//new后面是需要开辟的数据类型括号里是这个类型的数值
//最后new会在堆区开辟一个4个字节的内存空间存储这个10并返回开辟好的地址给指针a
return a;
}
int main()
{
int* p = fun();
cout << *p << endl;//10
delete p;//释放开辟的堆区空间
system("pause");
return 0;
}
**注:**你使用new开辟的是什么数据类型,new开辟好这个数据类型大小的空间后就会返回一个这个数据类型的指针
delete释放空间:
delete后面放一个存储当前存储堆区开辟空间地址的指针变量就可以释放我们开辟的堆区空间。
cpp
int* p = new int(10);//开辟堆区空间并返回
delete p;//释放这块空间
2.3.2 new开辟数组
cpp
int* a = new int[10];
cpp
int* a = new int;
int* a = new int[10];
new后面数据类型决定开辟多大空间,int[10]是一种数组类型,new会所以开辟10个大小为int的空间
示例:
cpp
#include<iostream>
using namespace std;
int* fun()
{
int* a = new int[10];
for (int i = 0; i < 10; i++)
{
cin >> a[i];
}
return a;
}
int main()
{
int* p = fun();
for (int i = 0; i < 10; i++)
{
cout << p[i] << " ";
}
cout << endl;
delete[] p;//释放数组前面要加一个中括号才可以
system("pause");
return 0;
}
delete释放数组:
cpp
delete[] p;//释放数组前面要加一个中括号才可以
释放数组前面要加一个中括号才可以,告诉编译器这是一条很长的空间,这点一定要记得。