C++中的引用传递、按值传递、地址传递

本文详细介绍了C++中的引用,包括其基本使用、与指针的区别、常引用以及引用作为返回值的情况。引用作为变量的别名,提供了一种更安全、更简洁的指针替代方案,避免了野指针问题。同时,通过示例展示了引用在函数参数传递中的优势,尤其是在交换变量值时。此外,还强调了不应返回局部变量引用的原因,以及推荐的做法。
摘要由CSDN通过智能技术生成

一、引用的基本使用

  • 作用:给变量起别名
  • 语法:数据类型 &别名=原名

引用的本质就是带有const的指针 

int & a  = b <---> int *const a = &b
char & a = b <---> char *const a = &b
double & a = b  <---> double *const a = &b
(结构体类型) &a = b <---> (结构体类型) *const a = &b

为什么要C++要出现“引用”?
通过上面的对比,可以得出几条结论:

  • 引用比指针更加简化;
  • 引用使用起来更加像普通变量一样赋值;
  • 引用更加安全。因为新手一般不会定义 int *const a这样的指针,而是直接int * a,才会造成所谓的野指针(没有给指针初始化,不知道默认指向哪了),一个不小心修改野指针的内容,严重的可以导致电脑崩掉。
#include <iostream>
using namespace std;

int main()
{
  int a = 10;
  int &b = a;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;
  b = 100;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;
  cout<<"a address= "<<&a;
  cout<<", b address= "<<&b<<endl;
  return 0;
}

   运行结果:                      

 a = 10
 b = 10
 a = 100
 b = 100
 a address= 0x6dfee8 , b address= 0x6dfee8

Process returned 0 (0x0)   execution time : 0.368 s
Press any key to continue.

由上述运行结果得出以下结论:

  • a,b任一变量改变,a,b变量都改变
  • a,b的值和地址都相同

二、C++ 引用 vs 指针

引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

下面我们通过引用传递、按值传递、按地址传递来体会引用与指针的不同

#include <iostream>
using namespace std;

void swapr(int &a,int &b);
void swapp(int *p,int *q);
void swapv(int a, int b);

int main()
{
    int wallet1=300;
    int wallet2=350;

    cout <<"wallet1=$ "<<wallet1;
    cout <<"wallet2=$ "<<wallet2<<endl;

    cout<<"Using references to swap contents:\n";
    swapr(wallet1,wallet2);
    cout<<"wallet1 =$ "<<wallet1;
    cout<<"wallet2 =$ "<<wallet2<<endl;


    cout<<"Using pointers to swap contents again:\n";
    swapp(&wallet1,&wallet2);
     cout<<"wallet1 =$ "<<wallet1;
    cout<<"wallet2 =$ "<<wallet2<<endl;


    cout<<"Trying to use passing by value:\n";
    swapv(wallet1,wallet2);
     cout<<"wallet1 =$ "<<wallet1;
    cout<<"wallet2 =$ "<<wallet2<<endl;
   
 return 0;
}

 //引用传递
  void swapr(int &a,int &b)
  {
      int temp;
      temp=a;
      a=b;
      b=temp;
  }


//按地址传递(引用传递)

  void swapp(int *p,int *q)
  {
      int temp ;
      temp=*p;
      *p=*q;
      *q=temp;
  }

//按值传递

 void swapv(int a,int b)
 {
     int temp;
     temp=a;
     a=b;
     b=temp;
 }








运行结果

wallet1=$300wallet2=$350
Using references to swap contents:
wallet1 =$ 350wallet2 =$ 300
Using pointers to swap contents again:
wallet1 =$ 300wallet2 =$ 350
Trying to use passing by value:
wallet1 =$ 300wallet2 =$ 350

Process returned 0 (0x0)   execution time : 0.556 s
Press any key to continue.

总结: 

 1、若采用指针传递的方式,我们在函数定义和函数声明时使用 *来修饰形参,表示这个变量是指针类型;在进行函数调用时,使用 & 来修饰实参,表示是将该变量的地址作为参数传入函数。

2、引用实际上是某一个变量的别名,和这个变量具有相同的内存空间。 实参把变量传递给形参引用,相当于形参是实参变量的别名,对形参的修改都是直接修改实参。在类的成员函数中经常用到类的引用对象作为形参,大大的提高代码的效率

  • 按值传递、引用传递的相同与不同

相同点:调用过程相同

swapr(wallet1,wallet2);
swapv(wallet1,wallet2);

不同点:外在区别:声明函数的参数的方式不同

void swapr(int &a,int &b);
void swapv(int a, int b);

内在区别:在swapr()中,变量a和b是wallet1和wallet2的别名,所以交换a 和b的值相当于交换wallet1和wallet2的值;但在swapv()中,变量a和 b是复制wallet1和wallet2的值的新变量,因此交换a与b的值并不会影响wallet1与wallet2的值。

三、常引用

如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。

常引用声明方式:const 类型标识符 &引用名=目标变量名;

用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。

int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确

四、引用作为返回值

要以引用返回函数值,则函数定义时要按以下格式:

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

  • 不要作为返回局部变量的引用
#include <iostream>
using namespace std;
int &plus10(int &r) {
    int m = r + 10;
    return m;  //返回局部数据的引用
}
int main() {
    int num1 = 10;
    int num2 = plus10(num1);
    cout << num2 << endl;
    int &num3 = plus10(num1);
    int &num4 = plus10(num3);
    cout << num3 << " " << num4 << endl;
    return 0;
}

注意:

不同的编译器对于返回局部变量的引用有所区别对待:

对于gcc、codeblocks和g++, 编译报警告,运行的时候会出现错误
对于msvc:编译报警告,warning C4172: 返回局部变量或临时变量的地址: n,但是运行的时候不会出现错误,而是像正常的运行一样,比如上面的代码结果为5.

为什么不要返回局部变量的引用呢?

因为当该函数调用结束之后,该函数内部创建的局部变量出了作用域会被销毁,为这个函数开辟的栈帧也会被系统回收,在调用下一个函数之前会对这一部分栈空间里的垃圾数据进行清理,因此你也会失去对这个空间的管控能力。

  • 返回全局变量的引用
#include <iostream>
using namespace std;

int &plus10(int &r) {
    r += 10;
    return r;
}

int main()
{
    int num1 = 10;
    int num2 = plus10(num1);//用num2接受返回值
    cout << num1 << " " << num2 << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值