指针,引用与参数传递

  今天在编写双链表代码时遇到了这样的困惑:函数参数传递时形参声明为
1 strunct queue *&Q;
想了半天*&Q的含义,百思不得其解,于是查阅了很多关于指针和引用的资料,总算解决了困惑。

    首先,简单回顾一下指针引用这两种运算。
1 int val;
2 int *pv = &val; //指针声明
3 int &rv = val; //引用声明

当对引用类型初始化时,表示rvval相关联,也可以理解为rvval的别名,rvval共用一块内存,地址相同,值相同。而&val&出现在赋值号右边后成为了右值表达式,是一个常量,表示val的地址,这样我们可以把int *pv=&val理解为声明一个int*(指向int类型)的指针pv被赋值为int型变量val的地址

  1. 指针作为函数参数传递时,传递的是地址,对于函数
    1 void swap(int *lhs,int *rhs){
    2     int *temp;
    3     *temp = *lhs;
    4     *lhs = *rhs;
    5     *rhs = *temp;
    6 }
    我们
    1 int a,b;
    2 swap(&a,&b);
    这时有lhs=&a;rhs=&b;相当于把a,b的地址作为函数参数进行了传递,进行swap操作,交换的是地址内a,b变量的值,并非地址的交换,所以可以交换成功。如若改成
    1 void swap(int *lhs,int *rhs){
    2     int *temp;
    3     temp = lhs;
    4     lhs = rhs;
    5     rhs = temp;
    6 }
    则不能交换成功,因为传递的是地址(传递的是lhs(int *)rhs(int *))函数返回时ab地址恢复原值。
  2. 引用作为函数参数传递时,传递的是变量的引用(别名),而改变别名的变量时原来名字的变量也会改变,对于函数
    1 void swap(int &lhs,int &rhs){
    2     int temp;
    3     temp = lhs;
    4     lhs = rhs;
    5     rhs = temp;
    6 }
    我们
    1 int a,b;
    2 swap(a,b)
    lhs,rhsa,b的引用(别名),我们通过交换lhsrhs直接交换了a,b的值,函数返回时的lhsrhs不变
  3. 指针的指针作为参数传递,什么情况会会现这种情况呢,就是我们想通过函数改变的变量是指针,比如
    1 int *pa = &a;
    2 int *pb = &b;
    我们想交换papbab的地址),这时可以用到指针的指针做参数传递了
    1 void swap(int **lhs,int **rhs){
    2     int **temp;
    3     *temp = *lhs;
    4     *lhs = *rhs;
    5     *rhs = *temp;
    6 }
    我们
    1 swap(&a,&b);
    参数传递时
    1 int* *lhs = &pa; //pa是int *类型
    2 int* *rhs = &pb; //pb是int *类型
    **lhs的含义就是指向指针的指针的地址变量lhs&(pa)是对一个int型的指针变量pa求地址,指向int *的指针是int **型的,所以是&a作为参数传递最终改变了papb的值,也就是改变了ab的地址,交换成功。
  4. 最后一种,指针的引用作为参数传递,对于函数
    1 void swap(int &*lhs,int &*rhs){
    2     int *temp;
    3     *temp = *lhs;
    4     *lhs = *rhs;
    5     *rhs = *temp;
    6 }
    我们
    1 int *pa = &a;
    2 int *pb = &b;
    3 swap(pa,pb);
    参数传递时的赋值表达式应为
    1 & *lhs = pa; //pa为int *类型
    2 & *rhs = pb; //pb为int *类型
    通过交换*lhs*rhs直接交换了pa,pb的值,也就是,*pa*pb的地址没有发生变化,直接改变的papb的值也就是&a&b,即ab的地址。
    最后来看这一段程序
 1 struct node
 2 {
 3        int data;
 4        struct node *next;
 5 };
 6  
 7 struct queue
 8 {
 9        struct node *head;
10        struct node *tail;
11 };
12 void init(struct queue*& queue)
13 {
14      queue->head = queue->tail = new struct node;
15      queue->head->next = NULL;
16 }
void init(struct queue *&queue);中参数传递采用了*&的方式,也就是传递一个queue *类型的指针变量的引用,那么
1  main(int argc, char *argv[])
2 {
3     struct queue *Q;
4     init(Q);
5 }
参数传递时
struct queue* &queue = Q;//Q为queue *类型的引用
queue->head = queue->tail = new struct node;
实际上是为Q->headQ->tail申请了动态内存空间,Q->headQ->tail都是struct node*类型,queue->head->nextqueue->headnext之间的连接符用->queue->head->next=NULL;实际是将Q->head->next赋值为空指针,queue->head->next不指向任何结点。既然Qqueue *的,那么我们可以用
1 void init(struct queue **queue);
2 struct queue *Q;
3 init(&Q)
的形式来传递queue *型的参数Q吗,答案是否定的,不修改init的函数体的话,传递时queuequeue**类型的,->head的左端只接受queue*类型,所以编译不能通过。
总结:
  1. 参数传递时改变实参值的两种种方式,a.地址传递时改变地址中的值。(指针,指针的指针)b.引用传递时改变别名的值(引用,指针的引用)
  2. 参数传递实参应该传递它的指针还是引用呢?这里可以这样考虑,如void func(int *&p),func(?)。应该明确的是int* &p=?应该左右类型匹配,所以?应该是int*型的int* &p=(int*)。而void func(int **p),func(?)中,int* *p=?应该满足?是int*类型的求地址运算,或者int** p=?满足?是int**类型的(但是这样参数传递没有什么太大的意义),所以?是&(int*)型的,int* *p=&(int*)左右匹配。
posted @ 2013-04-14 13:46  FingerDancing  阅读(692)  评论(0编辑  收藏  举报