C++ 引用详解:引用和指针的区别;按值传递,按引用传递和按指针传递的区别

引用定义:

1.引用是c++对c的重要扩充,是变量的一个别名,c++中&定义引用:类型 & 引用名 = 被引用对象

2.引用是别名,在声明的时候必须初始化,在实际的代码中主要用做函数的形参,作为目标的别名而使用

int a;
int &b = a;

引用特点:

1.引用是别名,在声明的时候必须初始化

2.在实际的代码中主要用做函数的形参,引用作为目标的别名而使用,并且引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名

3.对引用的修改,相当于对目标的修改

4.引用与原变量共享相同的值和地址

5.&在此不是求地址运算,而是起标识作用

6.引用本身不是一种数据类型,因此引用本身不占存储单元,系统不给引用分配存储单元。对引用求地址,就是对目标变量求地址。&b与&a相等

7.不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名

例1:

#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    int a = 10;
    int &b = a;
    cout  <<r <<"   " << a<<endl;
    b = 20;
    cout  <<r <<"   " << a<<endl;
    return 0;
}

结果10 10 和20 20

例2:

    1.
    int *a = nullptr;
    int * &ptr = a;           //ok,表示int*的引用ptr初始化为a
    int b = 10;
    ptr = &b;                 //ok, ptr是a的别名,是一个指针
    2.
    void &a = 3;              //error, 不合法的
                              //void只是在语法上相当于一个类型,本质上不是类型,没有任何一个变量或对象,其类型为void
    3.
    int a[10] = {0};
    int &b[10]  =  a;         //error,不能建立一个引用类型的数组
    4.
    int a;
    int &b = a;
    int & *ptr = &b;        // error,企图定义一个引用的指针 

为什么用引用:

1.按值传递,如果有很大的数据项,复制数据需要很长的时间,出现性能问题
(当然可以使用指针可避免)

c++:

1.按值传递
2.按引用传递,避免复制大量的数据开销,提高性能

引用和指针的差别:

引用:引用就是变量的一个别名,操作和对变量直接操作一样

指针:利用地址,直接指向存在存储器中的另一个地方的值。通过指针可以找到以它为地址的内存单元

1. 指针有自己的空间,引用只是别名

2.sizeof指针4,引用为对象实际大小

3.指针可以初始化为null,引用必须是一个已有对象,有空指针没有空引用,每一个引用都是有效的

4.指针和引用的++运算不同

5.返回动态内存分配的对象或内存,必须使用指针,引用可能内存泄漏

6.指针是变量,可以把指针再次赋值指向别处,而引用是别名,在建立的时候必须初始化,并且不会再关联其他不同的变量

7.由于指针也是变量,可以有指针变量的引用,但void引用不合法

8.引用的参数传递:传递引用给函数和传递指针给参数的效果是一样的。但是引用作为参数比指针有更清晰的语法

按值传递,按引用传递和按指针传递的区别

按值传递:   不对变量修改

按引用传递:对引用的修改和对原值修改是一样的

按指针传递:指针对值的修改,原值也会修改

例:

#include <iostream>
using namespace std;
//按值传递
void A(int val)
{
    val = 10;
}
//按引用传递
void B(int& val)
{
    val = 10;
}
//按指针传递
void C(int *pval)
{
    *pval = 10;
}
int main(int argc, char *argv[])
{
    int a = 1,b = 1,c = 1;
    A(a);
    B(b);
    C(&c);
    cout <<a <<"   " <<b<<"   "<<c <<endl;
    return 0;
}

输出结果:

a = 1,b= 10, c= 10

解析:

  • A:按值传递,a的值相当于传递堆栈上的一个副本,函数传递结束只是对副本进行了修改,在调用完foo后的a的值还是1
  • B:按引用传递,对引用的修改和对原值修改是一样的
  • C:按指针传递是,指针对值的修改,原值也会修改

常引用:

定义:不希望通过引用来改变原始变量的值时

const 类型标识符 & 引用名 = 被引用的变量名

    int a = 10;
    const int &b = a;
    b = 20;   
    a = 20;

编译报错,b试图修改a的值,虽然常引用无法修改原始变量的值,但仍然可以通过原始变量自身来修改原始变量的值。

为什么使用引用参数?

在C系列语言中,函数只能返回一个值,但程序需要返回两个值怎么办?

解决方案之一:用引用给函数传递两个参数,然后由函数往目标中填入正确的值。

函数返回值时,要生成一个值的副本,而引用返回值的时候不需要生成副本,所以提高了性能。

注意:

如果返回不在作用域内的变量或者对象的引用就有问题了,这与返回一个局部作用域指针的性质一样严重。

因为,当函数调用完成,局部变量就会被销毁。而此时我们若将局部变量的值通过引用返回拷贝给目标变量的时候,有可能会出现在拷贝之前局部变量已经被销毁,从而导致目标变量获取不到返回值。

普通的传值返回则不存在这样的问题,因为编译器会将返回值拷贝到临时存储空间后再去销毁局部变量的。

虽然这种情况在一些编译器中并没有发生,但在设计程序的时候也应该尽量避免这一点。

1.
int res = 0
int& func (int a)     
{
    res = a * a;
    return res;     //ok,返回引用,res的值在函数的作用域之外
}

2.
int& func (int a)
{
    int res = 0;
    res = a * a;
    return res;       //error,返回局部变量的引用
}
      
int main()
{
    int  &val  =  func(5);     // error,返回的引用是个局部变量,当程序结束以后,会自动销毁(堆栈)
    return 0;
}
    

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值