C++:指针和引用

引用的概念及用法 
所谓的引用并非说从新定义的一个新的变量,而是给一个已经定义好了的变量起的一个别名。 
下面看看引用究竟是如何使用的:函数

void test1()
{
    int a = 1;
    int& b = a; //引用变量b是a的别名学习

    std::cout<<"a:address->"<<&a<<std::endl;
    std::cout<<"A:address->"<<&b<<std::endl;  //注意这里的&是取地址指针

    a = 10;
    b = 100;
    std::cout<<"a = "<<a<<std::endl;
    std::cout<<"b = "<<b<<std::endl;对象

    int& c = b; //应用变量c是引用变量b的别名,别名的别名
    c = 1000;
    std::cout<<"a = "<<a<<std::endl;
    std::cout<<"b = "<<b<<std::endl;
    std::cout<<"c = "<<c<<std::endl;
}

运行结果以下: blog


 
由结果咱们能够看出引用变m量b与变量a的地址是同样的,该变b的值也会影响a。而且一个变量能够取多个别名,这里b是a的别名,c是b的别名,也就是a的别名了。就像咱们人同样,你有一个大名(身份证上的名字),可能还会有一个小名,也或许还会给本身起一个洋气的英文名,总之无论别人叫哪个名字,叫的都是你本人就对了。内存

总结: 
一、一个变量能够有多个别名 
二、引用必须初始化b 
三、引用只能在初始化的时候引用一次,以后不能再引用其余的变量作用域

引用作参数 
在以前的学习当中,咱们知道调用函数的传参有传值调用和传址调用。下面再来看一看这两种方式:test

一、传值调用变量

void swap(int a,in b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
//如今的咱们都知道了这样的函数是没法完成咱们但愿的交换功能的。
//究其缘由,就是由于这里使用的是传值方式,那么若是别人一旦想要
//调用我给我传两个参数,我就要生成两个局部的临时变量用来接收
//别人给我传的两个参数。可是当调用结束,函数栈帧释放,相应的
//用于接收参数的两个局部变量也会被一同释放掉,可是交换是发生在
//这两个局部变量之间的,如今他们已经被释放掉了,而且从头至尾
//都没有对调用方的两个想要交换的变量产生任何影响。所以这里的
//传值调用并完成不了交换的功能。

二、传址调用语法

void swap(int *a,int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
//所谓的传址调用就是传指针。
//如今咱们将两个形参改成指针,也就是说别人想要调用我完成交换功能时
//就将想要交换的两个变量的地址传给我就行了。函数调用期间对地址里面
//的内容进行交换,即使调用结束之后,函数栈帧被释放,可是是对两个地址
//的内容进行了交换,释放栈帧之后这两个地址并非函数栈帧里的,
//因此并不会一并被释放,而且完成了交换的功能。

三、传引用

void swap(int& a,int& b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
//咱们知道引用变量就是咱们给一个已经定义好的变量起的一个别名,
//因此说,若是咱们这里采用传引用的方式,那咱们这里的形参就是实参的别名
//在刚刚咱们也看了,变量和变量的别名,他们两个的地址是同一个,因此啊,
//这和传址调用有着殊途同归之妙。

引用作返回值

有时候咱们一个函数调用结束须要返回一些信息供调用方使用。好比说一个加法函数。

//方法一
int ADD(int a,int b)
{
    int ret = a+b;
    return ret;
}
//方法二
int& ADD(int a,int b)
{
    int ret = a+b;
    return ret;
}
//这里方法一是采用值的形式返回,而方法2是采用引用的形式返回。
//咱们能够看看汇编语言是如何这两种不一样返回方式的,以下图:

 


 
那么问题来了,咱们有该如何选择以那种方式返回呢???

一、若是返回的对象出了该函数做用域依旧存在,则使用引用返回,由于这样会更加高效 
二、若是返回对象处了函数的做用域就不存在了,则使用值返回。 
注意:不要返回一个临时变量的引用,由于临时变量在函数调用结束之后会随着栈帧的释放而被释放,而传引用返回的方式返回的是变量的地址,而事实是该变量已经被释放。

引用和指针的区别 
在这以前咱们一直在说,引用是一个变量的别名,因此可能就会想到说这个引用变量时不会占据任何的空间的。可是!请注意!这种想法是不对的。引用变量也是会占据必定的内存空间的,也须要在栈上额外占用存储空间。 
由于引用的底层实现实际上是指针。从语法上来看只是一个别名,但在底层上依旧是开辟了一块空间。

int main()
{
    int a = 0;
    int& b = a;
    return 0;
}

看一下这段代码的汇编:是如何处理变量a,和引用变量b 


 
从汇编咱们能够看出对引用变量初始化为a的别名,就是将a的地址给了引用变量b。想想这种方式是否是很熟悉?对了,正如你所想到的咱们常常写的一个代码:

int a = 0;
int *p = &a;
//取a的地址赋给指针变量p

这样看来其实引用的底层也就是一个指针,只不过明面上向咱们所展现的是一个变量的别名,但咱们应该注意引用变量是一个已经定义过的变量的别名,他是别名,他也占空间,由于他的底层实现是指针。

下面就看一看引用和指针的区别:

一、引用只能在定义时初始化一次,以后不能改变指向其余的变量,但指针能够。  二、引用必须指向有效的变量,但指针能够为空。  三、sizeof引用获得的是所指向的变量的大小,但sizeof指针是对象的地址的大小。  四、引用的自增(+ +)自减(- -)是对值的+1或-1,而指针++或–是+或-其所指向的类型大小。  

相关文章
相关标签/搜索