c++内存模型、引用及函数

44 阅读4分钟

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;
}

3、函数高级

函数默认参数

在c++中函数的形参列表中的参数是可以有默认值的;

在函数中如果某个参数有默认值,那么它后面的所有参数都得有默认参数;

如果函数声明有默认参数,那么函数的定义就不能有默认参数

//如果我们有传入数据,就用传入的数据,没有的话就用默认数据
int func01(int a, int b = 10, int c = 10) {
	return a + b + c;
}

//函数声明,存在默认参数
int func02(int a, int b = 10);
//那么在函数定义时就不能有默认参数
int func02(int a, int b) {
	return a + b;
}

int main()
{
	cout << func01(1, 4) << endl;//15
	cout << func01(1) << endl;  //21
	cout << func02(1) << endl; //11
	system("pause");
	return 0;
}

函数占位参数

c++中函数的形参列表可以有占位参数,用来占位,调用函数时必须填补该位置

占位参数还可以有默认值

//占位参数,设置了默认值
void func(int a, int = 5) {
	cout << "This is a function " << endl;
	cout << a << endl;
}

int main() {
    //调用函数时填补占位参数
	func(12, 9);
	system("pause");
	return 0;
}

函数重载

重载:函数名称相同,函数参数类型不同或者个数不同或者顺序不同

void func() {
	cout << "This is a function  01 " << endl;
}

void func(int a) {
	cout << "This is a function  02" << endl;
}
void func(double a) {
	cout << "This is a function  03" << endl;
}

void func(int a,double b) {
	cout << "This is a function  04" << endl;
}
void func(double a, int b) {
	cout << "This is a function  05" << endl;
}

注意事项:

  • 引用可以作为重载条件
  • 重载时避免出现默认参数,会出现二义性