1、c++内存模型
c++程序执行时将内存大致分为4个区域
- 代码区:存放CPU执行的二进制代码指令,由操作系统进行管理
- 全局区:存放全局变量和静态变量以及全局常量和字符串常量
- 栈区:由编译器自动编译释放,存放函数的参数值,局部变量等
- 堆区:由程序员分配释放,如果程序员不释放,则程序结束时由操作系统回收
c++内存模型图如下:
代码区特点
共享的:对于频繁执行的程序,在内存中只要有一份代码即可
只读的:防止系统意外修改它的指令
全局区特点
该区域的数据,在程序结束后由操作系统释放
栈区特点
由编译器自动编译释放,存放函数的参数值,局部变量等
注意事项:栈区编译的数据执行完后由编译器自动释放,不要返回局部变量的地址
堆区特点
由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在c++中主要通过new关键字在堆区开辟内存
new 和delete关键字
new关键字开辟内存
elete关键字释放指针p指向的内存
int* func()
{
//用new关键字开辟内存,new返回的是该数据的指针
int * p = new int(21);
return p;
}
int main()
{
int * p = func();
cout << *p << endl;
//使用delete关键字释放指针p指向的内存
delete p;
system("pause");
return 0;
}
2、引用
引用可以看做是变量的一个别名,通过这个别名和原来的名字都能够找到这个变量。
语法:
//数据类型 &别名 = 原名
int a = 10;
int &b = a;
注意事项:引用必须在定义的同时初始化,并且以后也要从一而终,不能再引用其它变量。
引用作为函数参数
将函数的形参指定为引用的形式,这样在调用函数时就会将实参和形参绑定在一起,让它们都指代同一个变量。如此一来,如果在函数体中修改了形参的值,那么实参的值也会被修改。
//引用传递,&a1,&b1分别是变量a和b的引用
void swap(int &a1,int &b1)
{
int temp = a1;
a1 = b1;
b1 = temp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
cout << a << "\n" << b << endl;
system("pause");
return 0;
}
引用作为函数返回值
不能返回局部数据(例如局部变量、局部对象、局部数组等)的引用,因为当函数调用完成后局部数据就会被销毁,有可能在下次使用时数据就不存在了,C++ 编译器检测到该行为时也会给出警告。
int& test() {
static int a = 10;//这里把a变成静态变量,存放在全局区,全局区的数据在程序结束后由系统释放
return a;
}
int main()
{
int &ref = test();
cout << ref << endl; //10
test() = 1000;//如果函数的返回值是引用,这个函数调用可以作为左值
cout << ref << endl; //1000
system("pause");
return 0;
}
引用的本质
引用的本质是一个指针常量,所有指针操作由编译器完成。
常量引用
常量引用主要用来修饰形参,防止误操作;
在函数中可以用const修饰形参,防止形参改变实参
void showValue(const int& a1) {
// a1+=1000; 不允许修改
cout << a1 << endl;
}
int main()
{
int a = 10;
showValue(a);
system("pause");
return 0;
}