1 | /********************************************************* |
2 | * Desc:参数传递:使用引用传递指针和直接传递指针地址的区别 |
4 | * DateTime:2010-12-7 11:00 |
02 | ***********************************************************/ |
09 | void swapByRef( int *&, int *&); |
10 | void swapByPoi( int *, int *); |
20 | cout<< "调用swapByRef()之前:pi=" <<pi<< ",*pi=" <<*pi<< ";pj=" <<pj<< ",*pj=" <<*pj<<endl; |
22 | cout<< "调用swapByRef()之后:pi=" <<pi<< ",*pi=" <<*pi<< ";pj=" <<pj<< ",*pj=" <<*pj<<endl; |
24 | cout<< "**********************" <<endl; |
27 | cout<< "调用swapByPoi()之前:pi=" <<pi<< ",*pi=" <<*pi<< ";pj=" <<pj<< ",*pj=" <<*pj<<endl; |
30 | cout<< "调用swapByPoi()之后:pi=" <<pi<< ",*pi=" <<*pi<< ";pj=" <<pj<< ",*pj=" <<*pj<<endl; |
42 | void swapByRef( int *&v1, int *&v2) |
55 | void swapByPoi( int *v1, int *v2) |
执行结果:
从结果可以看出:
1. swapByRef方法是直接交换参数的指针执行的地址,所以指针指向的内容也换了
2. swapByPoi方法只是操作指针指向的内容,指针执行的地址未变化
#include <stdio.h>
void swap(int x,int y)//这是错误的写法
{
int temp;
temp=x;
x=y;
y=temp;
}
int main()
{
int a=5,b=8;
swap(a,b);
printf("%d %d\n",a,b);
return 0;
}
代码很容易理解,就是交换2个变量a和b的值并输出,但是运行后我们发现输出结果不是"8 5"而依旧是"5 8",也就是说交换函数并没有将2个变量的值交换,这是为什么呢?
我们知道,C语言中整型变量的形式参数传递的是值而不是地址,也就是形式参数实际上是复制了实际参数的值进入函数运算的,而被复制的实际参数的值并没有改变。就这段代码来说,就是形参x复制了a的值变成5,形参y复制了b的值变成8,然后在swap函数中进行交换,使得x=8,y=5,但实际上a和b的值并没有被交换,这也就是为什么这段代码并没有实现交换的原因。
那么怎么解决呢?
先前我们说了C语言中整型变量的形式参数传递的是值而不是地址,那么现在我们就让它传递地址,直接交换实际参数的值。
#include <stdio.h>
void swap(int *x,int *y)//使用指针传递地址
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
int main()
{
int a=5,b=8;
swap(&a,&b);
printf("%d %d\n",a,b);
return 0;
}
我们使用指针变量来进行地址传递,形式参数为变量a和b的地址,swap函数直接交换a和b的地址所指向的值。这里一定注意形式参数传递的是地址而不是值
int n;
int &m = n;
在C++中,多了一个C语言没有的引用声明符&,如上,m就是n的引用,简单的说m就是n的别名,两者在内存中占同样的位置,不对m开辟新的内存空间,对m的任何操作,对n来说是一样的。
对于引用,有以下三条规则:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
假如在一个函数中动态申请内存空间,用指针和用引用作形参会得到不同的结果,如下面的例子:
void fun(int* b){ //用指针做形参
b = (int*)malloc(sizeof(int)*3);
for(int i=0; i<3; i++){
a[i] = i;
}
}
void fun(int* &b){ //用引用做形参
b = (int*)malloc(sizeof(int)*3);
for(int i=0; i<3; i++){
b[i] = i;
}
}
如果在main函数中定义了一个int型的空指针并分别作为实参传入,如下:
int main(){
int *a = NULL;
fun(a);
for(int i=0; i<3; i++){
cout << a[i] << " ";
}
cout << "\n";
return 0;
}
结果用指针的函数会出现内存访问出错,用引用的函数则运行正常并正确输出1 2 3.
这是因为:
1.指针虽然是地址传递,但实际上也是在函数中又定义了一个新的指针让其与传入的指针指向同一地址。但两个指针本身作为变量在内存中的存放地址是不同的,就是说这是两个不同的变量,只是内容(即所指地址)相同。
2.在函数中对新定义的指针动态申请内存,但是当函数结束后,申请的内存的生命周期也就结束了,所以当回到主函数时,作为实参的指针地址和内容都没有变化。仍然是个空指针,对其进行访问自然出现了内存读错误了。
假如在main函数中这样写:
int *a = (int*)malloc(sizeof(int)*3);
就不会出现内存读错误了,但是输出结果还是错误的,道理也是一样的。
3.用引用作为实参传入时,fun函数中的b其实就是主函数中a的别名(或者叫外号),反正就是操作完全相同,地址相同,内容相同的一个变量,所以当fun函数返回时,对b的操作在主函数中对a同样有效。
再看一个例子:
int *a = NULL;
char* b = (char*)a;
int *a = NULL;
char* &b = (char*)a;
这一次是在编译阶段的区别:
用指针可以通过编译,而用引用则不可以,提示类型转换出错。
通过这两个例子可以看出,指针比引用灵活,也更加危险。
摘自『高质量c++编程』
条款一:指针与引用的区别
指针与引用看上去完全不同(指针用操作符’*’和’->’,引用使用操作符’.’),但是它们似乎有相同的功能。指针与引用都是让你间接引用其他对象。你如何决定在什么时候使用指针,在什么时候使用引用呢?
首先,要认识到在任何情况下都不能用指向空值的引用。一个引用必须总是指向某些对象。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。
PS:引用在定义时不可加const,否则编译出错,在形参前面则可以加const以确保在函数中该变量不会被修改。
个人认为:其实形参建立的是一个新的地址,只是这地址是实参内容的一个COPY,假如实参为p,形参就为_p;