C++是在C语言的基础上发展来的。C++除了有C语言的指针外,还增长一个新的概念——引用,初学者容易把引用和指针混淆一块儿,面试或者笔试常常被考到。面试
要弄清楚这两个概念,先从变量提及。数组
什么是变量呢?变量(variable)的定义在计算机科学中究竟是如何定义的?而后variable究竟是在内存中如何存储值的呢?那么跟着上面的问题,咱们来一一的解答。安全
首先最重要的,变量的定义,当你申明一个变量的时候,计算机会将指定的一块内存空间和变量名进行绑定;这个定义很简单,但其实很抽象,例如:int x = 5; 这是一句最简单的变量赋值语句了, 咱们常说“x等于5”,其实这种说法是错误的,x仅仅是变量的一个名字而已,它自己不等于任何值的。这条语句的正确翻译应该是:“将5赋值于名字叫作x的内存空间”,其本质是将值5赋值到一块内存空间,而这个内存空间名叫作x。切记:x只是简单的一个别名而已,x不等于任何值。其图示以下:数据结构
变量在内存中的操做实际上是须要通过2个步骤的:函数
1)找出与变量名相对应的内存地址。测试
2)根据找到的地址,取出该地址对应的内存空间里面的值进行操做。this
首先介绍到底什么是指针?指针变量和任何变量同样,也有变量名,和这个变量名对应的内存空间,只是指针的特殊之处在于:指针变量相对应的内存空间存储的值刚好是某个内存地址。这也是指针变量区别去其余变量的特征之一。例如某个指针的定义以下spa
int x = 5; int *ptr = &x;
ptr便是一个指正变量名。经过指针获取这个指针指向的内存中的值称为dereference,间接引用。.net
其相对于内存空间的表示以下:翻译
使用指针的优势和必要性:
指针可以有效的表示数据结构;
能动态分配内存,实现内存的自由管理;
能较方便的使用字符串;
便捷高效地使用数组
指针直接与数据的储存地址有关,好比:值传递不如地址传递高效,由于值传递先从实参的地址中取出值,再赋值给形参代入函数计算;而指针则把形参的地址直接指向实参地址,使用时直接取出数据,效率提升,特别在频繁赋值等状况下(注意:形参的改变会影响实参的值!)
引用是C++引入的新语言特性,是C++经常使用的一个重要内容之一。
引用(reference)在C++中也是常常被用到,尤为是在做为函数参数的时候,须要在函数内部修改更新函数外部的值的时候,能够说是引用场景很是丰富。正确、灵活地使用引用,可使程序简洁、高效。
我在工做中发现,许多人使用它仅仅是想固然,只是知道怎么应用而已,而不去具体分析这个reference。
在某些微妙的场合,很容易出错,究其起因,大多由于没有搞清本源。
下面我就来简单的分析一下这个reference。首先咱们必须明确的一点就是:reference是一种特殊的pointer。从这能够看出reference在内存中的存储结构应该跟上面的指针是同样的,也是存储的一块内存的地址。例如reference的定义以下:
int x = 5; int &y = x;
引用就是某一变量(目标)的一个别名,对引用的操做与对变量直接操做彻底同样。
引用的声明方法:类型标识符 &引用名=目标变量名;
上面的代码,定义了引用y,它是变量x的引用,别名,这样子,目标变量有两个名称,即该目标原名称和引用名,且不能再把该引用名做为其余变量名的别名。
(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:
int a=1;int *p=&a; int a=1;int &b=a;
上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。
而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。
(2) 引用不能够为空,当被建立的时候,必须初始化,初始化后就不会再改变了;而指针能够是空值,能够在任什么时候候被初始化,指针的值在初始化后能够改变,即指向其它的存储单元。
(3)能够有const指针,可是没有const引用;
(4)指针能够有多级,可是引用只能是一级(int **p;合法 而 int &&a是不合法的)
(5)”sizeof引用”获得的是所指向的变量(对象)的大小,而”sizeof指针”获得的是指针自己的大小;
(6)指针和引用的自增(++)运算意义不同;
(7)若是返回动态内存分配的对象或者内存,必须使用指针,引用可能引发内存泄漏;
(8)从内存分配上看,程序为指针变量分配内存区域,而不为引用分配内存区域,由于引用声明时必须初始化,从而指向一个已经存在的对象。引用不能指向空值。
注:标准没有规定引用要不要占用内存,也没有规定引用具体要怎么实现,具体随编译器 http://bbs.csdn.net/topics/320095541
(9)从编译上看,程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,所以指针能够改变指向的对象(指针变量中的值能够改),而引用对象不能改。这是使用指针不安全而使用引用安全的主要缘由。从某种意义上来讲引用能够被认为是不能改变的指针。
(10)不存在指向空值的引用这个事实,意味着使用引用的代码效率比使用指针的要高。由于在使用引用以前不须要测试它的合法性。相反,指针则应该老是被测试,防止其为空。
下面用通俗易懂的话来概述一下:
指针-对于一个类型T,T*就是指向T的指针类型,也即一个T*类型的变量可以保存一个T对象的地址,而类型T是能够加一些限定词的,如const、volatile等等。见下图,所示指针的含义:
引用-引用是一个对象的别名,主要用于函数参数和返回值类型,符号X&表示X类型的引用。见下图,所示引用的含义:
总之,能够归结为"指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名,引用不改变指向。"
在C++中,指针和引用常常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不一样的:
指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程当中,被调函数的形式参数做为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特色是被调函数对形式参数的任何操做都是做为局部变量进行,不会影响主调函数的实参变量的值。(这里是在说实参指针自己的地址值不会变)
而在引用传递过程当中,被调函数的形式参数虽然也做为局部变量在栈中开辟了内存空间,可是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操做都被处理成间接寻址,即经过栈中存放的地址访问主调函数中的实参变量。正由于如此,被调函数对形参作的任何操做都影响了主调函数中的实参变量。
引用传递和指针传递是不一样的,虽然它们都是在被调函数栈空间上的一个局部变量,可是任何对于引用参数的处理都会经过一个间接寻址的方式操做到主调函数中的相关变量。而对于指针传递的参数,若是改变被调函数中的指针地址,它将影响不到主调函数的相关变量。若是想经过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。
C++返回引用类型
A& a(){ return *this;} 就生成了一个固定地址的指针,并把指针带给你。
但A a() { return *this;}会生成一个临时对象变量,并把这个临时变量给你,这样就多了一步操做。
当返回一个变量时,会产生拷贝。当返回一个引用时,不会发生拷贝,你能够将引用看做是一个变量的别名,就是其余的名字,引用和被引用的变量实际上是一个东西,只是有了两个名字而已。
问题的关键是,当你想要返回一个引用而不是一个拷贝时,你要确保这个引用的有效性,好比:
int & fun() { int a; a=10; return a; }
这样是不行的,由于a会在fun退出时被销毁,这时返回的a的引用是无效的。
这种状况下,若是fun的返回类型不是int & 而是int就没有问题了。
返回指针的话,谁调用该函数,谁负责接触返回的指针。
全局变量,局部静态变量,局部动态分配变量 均可以做为函数返回值。
局部自动变量不行
函数内部等局部变量,存储在栈中的变量是不能做为返回值的,虽然能够读取正确的值,可是这是一块未分配的内存,当别的进程用到时就会出错,这个指针至关于野指针。返回值能够是局部动态分配的内存空间,这一部分分配在堆上,在主动释放以前别的进程是没法使用的内存区域。
不论是指针仍是引用都是如此。
为何要提到const关键字呢?由于const对指针和引用的限定是有差异的:
★常量指针:指向常量的指针,在指针定义语句的类型前加const,表示指向的对象是常量。
定义指向常量的指针只限制指针的间接访问操做,而不能规定指针指向的值自己的操做规定性。
常量指针定义"const int* pointer=&a"告诉编译器,*pointer是常量,不能将*pointer做为左值进行操做。
★常量引用:指向常量的引用,在引用定义语句的类型前加const,表示指向的对象是常量。也跟指针同样不能对引用指向的变量进行从新赋值操做。
在指针定义语句的指针名前加const,表示指针自己是常量。在定义指针常量时必须初始化!而这是引用与生俱来的属性,无需使用const。
指针常量定义"int* const pointer=&b"告诉编译器,pointer(地址)是常量,不能做为左值进行操做,可是容许修改间接访问值,即*pointer(地址所指向内存的值)能够修改。
常量指针常量:指向常量的指针常量,能够定义一个指向常量的指针常量,它必须在定义时初始化。
定义"const int* const pointer=&c"
告诉编译器,pointer和*pointer都是常量,他们都不能做为左值进行操做。
而不存在所谓的"常量引用常量",由于引用变量就是引用常量。C++不区分变量的const引用和const变量的引用。程序决不能给引用自己从新赋值,使他指向另外一个变量,所以引用老是const的。若是对引用应用关键字const,起做用就是使其目标称为const变量。即
没有:const double const& a=1;
只有const double& a=1;
double b=1;
constdouble& a=b;
b=2;//正确
a=3;//出错error: assignment of read-only reference `a'
总结:有一个规则能够很好的区分const是修饰指针,仍是修饰指针指向的数据——画一条垂直穿过指针声明的星号(*),若是const出如今线的左边,指针指向的数据为常量;若是const出如今右边,指针自己为常量。而引用自己就是常量,即不能够改变指向。