指针,引用与参数传递
今天在编写双链表代码时遇到了这样的困惑:函数参数传递时形参声明为
1 strunct queue *&Q;
想了半天*&Q的含义,百思不得其解,于是查阅了很多关于指针和引用的资料,总算解决了困惑。
首先,简单回顾一下指针和引用这两种运算。
1 int val; 2 int *pv = &val; //指针声明 3 int &rv = val; //引用声明
当对引用类型初始化时,表示rv与val相关联,也可以理解为rv是val的别名,rv和val共用一块内存,地址相同,值相同。而&val中&出现在赋值号右边后成为了右值表达式,是一个常量,表示val的地址,这样我们可以把int *pv=&val理解为声明一个int*(指向int类型)的指针pv被赋值为int型变量val的地址。
- 指针作为函数参数传递时,传递的是地址,对于函数
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);
1 void swap(int *lhs,int *rhs){ 2 int *temp; 3 temp = lhs; 4 lhs = rhs; 5 rhs = temp; 6 }
- 引用作为函数参数传递时,传递的是变量的引用(别名),而改变别名的变量时原来名字的变量也会改变,对于函数
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)
- 指针的指针作为参数传递,什么情况会会现这种情况呢,就是我们想通过函数改变的变量是指针,比如
1 int *pa = &a; 2 int *pb = &b;
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 *类型
- 最后一种,指针的引用作为参数传递,对于函数
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 *类型
最后来看这一段程序
void init(struct queue *&queue);中参数传递采用了*&的方式,也就是传递一个queue *类型的指针变量的引用,那么
参数传递时
实际上是为Q->head,Q->tail申请了动态内存空间,Q->head和Q->tail都是struct node*类型,queue->head->next中queue->head与next之间的连接符用->,queue->head->next=NULL;实际是将Q->head->next赋值为空指针,queue->head->next不指向任何结点。既然Q是queue *的,那么我们可以用
的形式来传递queue *型的参数Q吗,答案是否定的,不修改init的函数体的话,传递时queue是queue**类型的,->head的左端只接受queue*类型,所以编译不能通过。
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 }
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;
1 void init(struct queue **queue); 2 struct queue *Q; 3 init(&Q)
总结:
- 参数传递时改变实参值的两种种方式,a.地址传递时改变地址中的值。(指针,指针的指针)b.引用传递时改变别名的值(引用,指针的引用)
- 参数传递实参应该传递它的指针还是引用呢?这里可以这样考虑,如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*)左右匹配。
如果你交给某人一个程序,你将折磨他一整天;如果你教某人如何编写程序,你将折磨他一辈子。