C++中指针 & 引用 & const

引用

  • 定义:引用可以理解成给变量多起了一个别名。
  • 格式:类型 & 引用变量名=原变量名
    比如
int a=10;
int &b=a;
b=20;

定义变量a的值为10,又定义一个变量b作为a的别名,这是a和b表示同一块儿空间的值,改变b的值为20,a的值也改变。

  • 引用的特点
    (1)一个变量可以有多个别名
    (2)引用必须要初始化
    (3)引用只能在初始化的时候改变一次,之后不能再做修改。

  • 当引用作为参数时
    (1)值传递:如果使用 非引用的方式 进行传值,则生成临时变量接收实参的值

void fun(int a,int b){
    ;
}
void test{
    fun (a,b);
}
   和c语言函数中一样,如果不传实参的地址,则函数中的形参是实参的一份临时拷贝,值相同,
   但是是不同的变量,且函数的调用结束后,随栈帧一并销毁。

(2)用引用传递

void fun(int &a,int &b)

和c语言函数中传地址意义相同,函数中改变a和b,会对实参造成影响

(3)当不希望函数内改变参数的值时,尽量使用常引用传参

void fun(const int &a)

这里就保护了a在函数fun中不变。

  • 传值做返回值&传引用作为返回值
int add(int a,int b)
{
    int ret=a+b;
    return ret;
}

int main()
{
    int a=add(1,2);
    add(10,20);
    cout<<a<<endl;
}

上述代码中输出的a的值是3。

int &add(int a,int b)
{
    int ret=a+b;
    return ret;
}

int main()
{
    int &a=add(1,2);
    add(10,20);
    cout<<a<<endl;

上述代码输出的a的值是30.

这是怎么回事?
这里写图片描述

第一段代码中,,add(1,2)得出结果ret=3,ret在传递回main函数时,生成一份临时变量,a接收的就是这份临时变量的值。之后的代码再跟a没有关系。

第二段中函数的返回值类型是 int& ,这说明返回值是ret的别名,跳过了临时变量的生成。当add(10,20)函数开始调用时,将生成相应的栈帧,因为函数相同,栈帧与add(1,2)时没有变化,ret也在原来add(1,2)的位置由3改成了30。而a又是ret的别名,所以a的值也被修改成了30。

  • 结论:
    1.不要返回一个临时变量的引用(因为在之后的函数调用中,该临时变量所在的空间可能会分配给别的栈帧,并被使用并赋值)
    2.如果返回对象出了当前函数的作用域后仍然存在(比如静态变量),则最好用引用返回(这样就少了一次临时拷贝,更高效)

  • 引用和指针的区别和联系
    1.引用只能在定义时初始化一次,之后不能修改,而指针可以任意修改
    2.引用不能为空,指针可以为空
    3.sizeof(引用名)所得是引用的变量本身的大小,sizeof(指针名)是对象地址的大小
    4.指针和引用的增减意义不同
    5.引用更安全,指针有空指针和野指针的存在,相对讲不太安全。


const

const关键字能保护修饰的对象只能被读取,不能被修改。
在这里着重讲一下const 修饰指针和引用时要注意的问题。
这里写图片描述

1  const int *p;
2  int const *p;
3  int* const p;
4  const int* const p;

首先要分清const 位于不同位置时修饰的含义(假设p指向变量a):
当const位于*之前,修饰的是*p,(即变量a的值是只读的)
当const位于*之后,修饰的是p变量本身,(变量p内存储的是a的地址,p只读意思就是只能存a地址,不能再存别的变量的地址(比如b))。

理清这一点后来看一下代码:

int a=10;
(1)
const int* p1=&a;    //错误
int *p2=p1;

(2)
int const*p1=&a;     //错误
int *p2=p1;

(3)
int* const p1=&a;    //正确
int *p2=p1;

(4)
const int a=10;      //错误
int &b=a;

(5)
const int a=10;      //正确
int b=a;

(1)中const修饰 *p1, *p1只读,而p2也指向a, *p2的改变会影响 *p1,所以错误。
(2)与(1)相同
(3)中const修饰的是p1本身,p1只读,而p2也指向a,p2的改变不会影响p1,所以正确。
(4)中const修饰的是a,a只读,b作为a的别名,修改b也会影响a,所以错误。
(5)中const修饰的是a,把a的值赋给b,a和b是不同的两个变量,互不影响,所以正确。

根据以上的分析能得出一个结论:
在指针和引用前加const,一定要注意后面的代码不能使访问的权利扩大

比如 :

只读–>可读可写

以下权限缩小,不变都是可行的:

可读可写–>可读可写
可读–>可读
可读可写–>可读

猜你喜欢

转载自blog.csdn.net/Ferlan/article/details/80561293