c++引用与指针的区别以及引用实例
- 相同点:
- 都是地址的概念:
指针指向一块内存,它的内容是所指内存的地址;
引用是某块内存的别名。
- 不同点:
- 指针是一个实体,而引用仅仅是个别名;
int a=3; int &ra = a;
(1)&在此不是求地址运算,而是起标识作用
(2)类型标识符是指目标变量的类型
(3)声明引用时,必须同时对其进行初始化
(4)引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名(int b;int &ra=b 是不可以的)
(5)声明一个引用,不是新定义一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。所以对引用求地址,就是对目标变量求地址(&ra == &a)
(6)不能建立数组的引用,因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。
(7)引用中是没有const,指针有const ,const的指针不可改变
(8)引用不能为空,指针可以为空
小总结:引用只能在定义时被初始化一次,之后不可变;指针是可以改变的,引用从一而终;
#include <iostream> #include <string> using namespace std; int main() { int a = 10; int b = 20; int &rn = a; cout <<"rn="<< rn << " | " <<"a="<<a <<endl; cout << "&rn="<< &rn<< " | " <<"&a="<<&a<<" | " <<"&b="<<&b <<endl; cout <<"-------------------------------"<<endl; rn = b; cout <<"rn="<< rn <<" | "<<"a="<<a<<" | "<<"b="<<b<<endl; cout << "&rn="<< &rn<< " | " <<"&a="<<&a <<" | " <<"&b="<<&b <<endl; cout <<"-------------------------------"<<endl; rn = 100; cout <<"rn="<< rn <<" | "<<"a="<<a<<" | "<<"b="<<b<<endl; cin.get(); return 0; }
运行结果如下:
说明:由于引用本身就是目标的一个别名,引用本身的地址是一个没有意义的值,所以在c++中是无法取得引用的内存地址的。取引用的地址就是取目标的地址,c++本身就根本不提供获取引用内存地址的方法。
引用的实例应用讲解
下面我们通过以下三个例子对照来说明引用:
1〉
#include <iostream> #include <string> using namespace std; float c; float test(float a,float b) { c = a*b; return c; } int main() { float pn = test(3.0f,1.2f); cout <<pn; cin.get(); return 0; }
说明:上面的代码中我们可能以为函数返回的就是变量c,这么想可能就错了,在一般情况下,通过函数的调用返回的值其实会在内存栈空间内自动产生一个临时变量temp,因此函数在return时,返回的是一个临时产生的副本而已!!
2〉我们把上面的例子加以修改
#include <iostream> #include <string> using namespace std; float c; float test(float a,float b) { c = a*b; return c; } int main() { float &pn = test(3.0f,1.2f); cout <<pn; cin.get(); return 0; }
说明:你会发现, 在vc++6.0编译器下会报错,出现error C2440: 'initializing' : cannot convert from 'float' to 'float &' A reference that is not to 'const' cannot be bound to a non-lvalue! 原因:一旦test()执行产生的临时变量在调用之后就会在栈空间内消失,这样pn也就成为一个没有明确目标的引用,严重的时候会出现内存错误!!
3〉我们再将以上代码进行修改!!希望大家把这个例子好好理解!
#include <iostream> #include <string> using namespace std; float c; float &test(float a,float b) { c = a*b; return c; } int main() { float pn = test(3.0f,1.2f); cout <<pn; cin.get(); return 0; }
说明:这种返回引用给变量的情况,在内存中,test()所在栈空间内并没有产生临时变量,而是直接将全局变量c赋值给pn,这种方式是我们最为推荐的操作方式,因为不产生临时变量直接赋值的方式可以节省内存空间提高效率,而且程序的可读性也好!!
1、引用作为参数:
引用作为参数讲,我们就会想起指针,最为典型的例子就是交换两个变量的值!!
a、针交换两个变量的值
#include <iostream> using namespace std; void swap1(int *m,int *n) { int t; t=*m; *m = *n; *n=t; } int main() { int a=3,b=2; int *pa = &a; int *pb = &b; cout <<"a = "<<a <<"--front--"<<"b ="<<b<<endl; swap1(pa,pb); cout <<"a = "<<a <<"--after--"<<"b ="<<b<<endl; return 0; }
b、用交换两个变量的值
#include <iostream> using namespace std; void swap1(int &m,int &n) { int t; t=m; m = n; n=t; } int main() { int a=3,b=2; cout <<"a = "<<a <<"--front--"<<"b ="<<b<<endl; swap1(a,b); cout <<"a = "<<a <<"--after--"<<"b ="<<b<<endl; return 0; }
从以上两段代码可以看出:1〉传递引用给函数与传递指针的效果是一样的!!,这时,被调用函数的形参就成为原来主调函数中的是残变量或对象的一个别名来使用,所以在被调用函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
2〉使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
总结:如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。
(后续--------)