稳扎稳打,记录点滴成长
1. 内存分区模型
1.1 程序运行前
程序编译后,生成了可执行程序,未执行该程序前,分为两个区域
注意1:常量分为 "字符串常量" 和 "被const修改的"常量两种
注意2:"被const修改的"常量 又分为全局常量(放全局区)和局部常量。
1.2 程序运行后
形参数据也会放在栈区
1.3 new操作符
// 堆区开辟一个存放10的整型数;并返回其地址
int *p = new int(10);
// 释放这个开辟的数
delete p;
// 堆区开辟一个有6个整型数成员的数组;并返回地址
int *arr = new int[6];
// 释放这个开辟的数组;注意释放数组时添加[]
delete[] arr;
2. 引用
2.1 引用的基本使用
2.2 引用的注意事项
1. 引用必须要初始化
int &b; //错误的
int a = 10;
int &b = a; //正确的
2. 引用一旦初始化后就不可以更改了
//延续上面代码
int c = 3;
b = c; //这是赋值操作不是原来的意思了,不是更改别名 =》引用不可以更改
2.3 引用做函数参数
作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针
通过引用参数产生的效果同地址传递是一样的。引用的语法更清楚简单。
2.4 引用做函数返回值
作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量的引用
int& Function(void)
{
int a = 10;
return a;
}
int main()
{
int &ret = Function(); //错误,就和值传递的方式一样,空间已经被释放了
}
用法:函数调用作为左值
int& Function()
{
static int b = 66; //静态变量存放再全局区,程序结束后由系统释放
return b;
}
int main()
{
int &ret2 = function();
cout << "ret2 = " << ret2 << endl;
function() = 6666; //做左值得本质,就是相当于a = 6666 这样的一个赋值操作
cout << "ret2 = " << ret2 << endl;
return 0;
}
//结果
//ret2 = 66
//ret2 = 6666
2.5 引用的本质
引用的本质再c++内部实现就是一个指针常量
引用一旦被初始化,就不可以发生改变
int main()
{
int a = 10;
int &data = a; // 等于常量指针int* const ref = &a, 也说明了引用不可更改的原因
ref = 20; // 等于 *ref = 20;
func(a);
return 0;
}
void func(int& ref) // int* const ref = &
{
ref = 100; // *ref = 20;
}
2.6 常量引用
作用:常量引用主要用来修改形参,防止误操作
在函数形参列表中,可以加const修饰形参,防止形参改变实参
3 函数提高
3.1 函数默认参数
int main()
{
function(10, 10, 10); //由默认参数自己重新传覆盖它可以,结果 = 30
function(10); //只传一个也可以,传值是从左至右传,结果 = 60
}
int function(int a, int b = 20, int c = 30)
{
return a + b +c;
}
//注意1:默认参数和传值相反,依次从右至左,不可以跳跃
int function(int a, int b = 20, int c) // 类似这样就是错误的
{
return a + b +c;
}
//注意2:声明和实现只能有一个有默认参数
// 假如像如下代码,计算机将无法判断是采用声明的还是实现的
int function(int a = 10, int b = 20);
int function(int a = 20, int b = 10)
{
return a + b;
}
// 以上这种错误,成为二异性,需要程序员自己注意,故统一采用声明处作为默认参数的初始化
3.2 函数占位参数
// 占位参数:函数名 (数据类型) {}
int function(int a = 20, int) // 其中第2个int就是一个占位参数
{
cout << "this is function" << endl;
}
// 占位参数可以有默认参数。例如如下:
int function(int a = 20, int = 10) // 其中第2个int就是带默认参数的占位参数
{
cout << "this is function too" << endl;
}
int main()
{
function(10, 10); // 调用时必须传入与之匹配的整型参数才可以正确调用
function(10); // 调用时可以不匹配默认参数相关位置
}
3.3 函数重载
3.3.1 函数重载概述
作用:函数名相同,可以提高函数复用性
// 函数重载
// 函数名相同
// 函数参数的类型、个数或者顺序任何一个不同即可重载,代码就不演示了
// 注意:不可以用函数返回值作为函数重载,例如下面的两个函数
void function(int a, char *b)
{
cout << "this is function A" << endl;
}
int function(int a, char *b)
{
cout << "this is function A" << endl;
}
// 为什么?
// 我理解,返回值已经是函数的结果了,但在执行时,计算机已经分辨不出该调用谁了
// 故,返回值不可以作为函数重载
3.3.2 函数重载注意事项
- 引用作为重载条件
- 函数重载碰到函数默认参数
// 引用作为重载条件
void function(int &a)
{
cout << "function(int &a)" << endl;
}
void function(const int &a)
{
cout << "function(const int &a)" << endl;
}
// 对于上面两个函数,因为int 和 const int 的区别,所以是可以发生函数重载的
int main()
{
int a = 10;
// 这个函数调用的是第一个function
// 因为a是一个变量,可读可写,所以计算机会走第一条函数
function(a);
// 如果传个常量值,就会调用第二条函数,原因如下:
// 原因1:因为10是一个可读不可写的
// 原因2:对于函数1,相当于int &a = 10 ,这是不合法的
// 但对于函数2,因为加了const =》取一个临时int temp = 10; const int &a = &temp,是合法的
function(10);
}
//函数重载碰到函数默认参数
void function(int a, int b = 10)
{
cout << "function(int a, int b = 10)" << endl;
}
void function(int a)
{
cout << "function(int a)" << endl;
}
// 调用时,下面方式调用,函数不知道走上面那条
// 这个就是默认参数引起的 二义性,会报错
// 故,在使用函数重载的时候,尽量不要使用默认参数
function(10);