【C++基础】浅谈C++中引用和指针的区别

引用是什么呢?

引用(reference)是C++引入的新语言特性,是C++常用的一个重要内容之一,正确、灵活地使用引用,可以使程序简洁、高效。

引用其实是给已经定义的变量起一个别名

定义的格式为: 类型 & 引用的变量名 = 已经定义的变量

引用这样几个特点:

1.一个变量可以起多个别名,也就是说可以进行多次引用

2.引用必须初始化

3.引用 只能在引用的时候初始化一次,不能改变引用,就是不能再去引用别的变量

例如:

    int a = 10;
    int& c = a;
    cout << "a address:" << &a << endl;
    cout << "c address:" << &c << endl;

c是a的别名,可以理解为,给变量a的又加了一个名字

引用作为函数参数

在C中,函数参数是值传递,如果想改变一些变量的时候就得用指针,这个可以提高效率,在C++中,我们可以选择引用,引用的其中一个重要的作用就是作为函数的参数,例如:

void Swap(int& a, int& b) {
    int tmp = a;
    a = b;
    b = tmp;
}

int main() {
    int a = 10;
    int b = 11;
    cout << "a = " << a << "b = " << b << endl;
    Swap(a, b);
    cout << "a = " << a << "b = " << b << endl;
    system("pause");
    return 0;
}

在上面的Swap函数中,形参是实参的别名,所以就可以直接更改。

根据上面的代码,我们分析可以得出以下几个结论:

1.引用的效果看起来和指针产生的效果是一样的

2.使用引用传递函数的参数,在内存中并没有产生一个新的变量,它是实参的别名,在函数内部是直接对实参进行操作的,当参数传递的数据较大时,使用引用的效果更好,不用为形参重新创建内存空间,而且效率也会更高

如果我们需要引用一个变量,但是又不想改变它,就可以在引用时加上const,使之成为常引用,例如:

    int a = 10;
    const int& b = a;
    a = 20;
    //错误,不能修改常量
    b = 10;

我们来看一下这样两行代码:

double c = 10.0;
int b = c;

在上面的赋值过程中,会有一个隐式的类型转换,先是创建一个临时变量,然后再把c复制给临时变量,然后再把临时变量的值进行截取,再赋值给b,那么再看下面的代码:

double c = 10.0;
int& b = c;

上面的代码是错误的,因为看似是引用c,但其实是想对那个临时变量取一个别名,临时变量具有常性,所以如果想要编译通过,就必须使用常引用,如:

double c = 20.0
const int& b = c;

这里写图片描述

引用作为返回值

引用还可以作为函数的返回值,用引用做返回值时,函数应该这样定义:

类型标识符 &函数名(形参列表及类型说明)
{函数体}

int fun1(int a, int b) {
    int c = a + b;
    return c;
}
int& fun2(int a, int b) {
    int c = a + b;
    return c;
}

int main() {
    int a = 10;
    int b = 20;
    //c1是fun1函数的返回值,30
    int c1 = fun1(a, b);
    //c2是在fun1中临时变量的别名,可能会出错,因为不能从被调函数中返回一个临时变量或局部变量的引用
    int& c2 = fun1(a, b);
    //c3是fun2的返回值,但是系统不会产生一个返回值的副本
    int c3 = fun2(a, b);
    //c4是函数fun2中变量c的所存在的内存空间的别名
    int& c4 = fun2(a, b);
    cout << c3 << endl;
    cout << c4 << endl;
    //因为在fun2函数之后还有cout函数的调用栈,所以c4的值是一个随机值

通过上面的例子,我们可以得出以下的结论:

1.不能返回局部变量的引用,因为局部变量会在函数完成后被销毁,即使能访问到也是一个随机值,这是个非法的操作。

2 如果返回对象出了当前函数的作用域依旧存在,则最好使用引用返回,因为这样更高效。

引用的特性

引用看似是给变量取了个别名,那么,具体是如何实现的呢?

int& Add(int a, int b) {
    int c = a + b;
    return c;
}

int main() {
    int a = 10;;
    int b = 20;
    int c = Add(a, b);
    system("pause");
    return 0;
}

看这段代码,引用做返回值,注意,引用不要做局部变量的返回值,但是这里的关注点不是这个,如图:

这里写图片描述

这个是在Add函数中的int c = a + b这个表达式的汇编代码,注意,前面三句的意思是,把a和b相加的值放在寄存器eax里面,然后再赋值给c,注意reutrn c这一句的汇编代码,lea eax , [c]这一句,是把c的地址放到eax里面,继续看图:

这里写图片描述

这是主函数中的Add函数的调用,前面已经看到了,eax里面存的是c的地址,注意看最后两句汇编代码,是把eax里面的地址的内容赋给edx,再把edx赋值给c

还有一个例子:

    int a = 10;;
    int b = 20;
//  int c = Add(a, b);
    int&c = a;

看汇编代码:

这里写图片描述

这几行代码,c是a的引用,跟上面一样,都是把a的地址给寄存器eax,然后再把寄存器eax存储的地址给变量c。

所以,引用虽然跟指针有很多不同,但是其底层还是用指针来实现的,那么,引用和指针有什么区别呢?

引用和指针的区别

引用和指针的区别有以下几点:

1.引用在创建的时候必须被初始化,而指针可以不初始化

2.引用被初始化后,就不能再改变了,而指针可以被改变

3.引用不能对不存在的变量进行引用,而指针可以指向NULL

4.指针和引用的自增(++)和自减(–)是有区别的(如果在数组中指针自增是指向下一个元素,而如果引用一个变量,然后自增,其实是给这个变量自增)

5.相对而言,引用比指针更安全

本质上,引用传递在底层上和指针传递的实现方式是一样的,我们可以认为引用仅仅是语法上的一种不同方法(有时称为“语法糖”)。什么是语法糖,举个例子,a[i]和(a+i)本质上是一样的,但a[i]的可读性更强,比(a+i)更加直观容易理解,语法糖使得程序更加不容易出错,更好用,而且也不会带来性能上的损失。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值