引用和指针

指针p也是对象,它同样有地址&p和存储的值p,只不过,p存储的数据类型是数据的地址。如果我们要以p中存储的数据为地址,来访问对象的值,则要在p前加解引用操作符"*",即*p

对象有常量(const)和变量之分,既然指针本身是对象,那么指针所存储的地址也有常量和变量之分,指针常量是指,指针这个对象所存储的地址是不可以改变的,而指向常量的指针的意思是,不能通过该指针来改变这个指针所指向的对象

我们可以把引用理解成变量的别名。定义一个引用的时候,程序把该引用和它的初始值绑定在一起,而不是拷贝它。计算机必须在声明r的同时就要对它初始化,并且,r一经声明,就不可以再和其它对象绑定在一起了。

实际上,你也可以把引用 看做是通过一个常量指针来实现的,它只能绑定到初始化它的对象上。

  1. int a,b,*p,&r=a;//正确
  2. r=3;//正确:等价于a=3
  3. int &rr;//出错:引用必须初始化
  4. p=&a;//正确:p中存储a的地址,即p指向a
  5. *p=4;//正确:p中存的是a的地址,对a所对应的存储空间存入值4
  6. p=&b//正确:p可以多次赋值,p存储b的地址
  7. int &b = 10; 错误 引用必须引一块合法的内存空间
  8. const int &b = 10; 正确,加入const -> int temp =10; const int &b = temp;
  9. b = 20; 错误,加入const之后变为只读不可以修改
  10. void func(const int &a)
  11. {
  12. a = 100; // assignment of read-only reference 'a'
  13. cout << "a = "<<a << endl;
  14. }

引用作为参数 形参与实参

形参出现在函数定义的地方,多个形参之间以逗号分隔,形参规定了一个函数所接受数据的类型和数量。

实参出现在函数调用的地方,实参的数量与类型与形参一样,实参用于初始化形参。

Swap1中a,b的交换,形参不会改变实参的数值;Swap2中的a,b的交换,由于变量的引用,形参会改变实参的数值。

  1. // 值传递
  2. void swap1(int a, int b)
  3. {
  4. int temp = a;
  5. a = b;
  6. b = temp;
  7. cout <<"swap1 "<< "a = " << a << " "
  8. << "b = " << b << endl;
  9. return;
  10. }
  11. // 引用传递
  12. void swap2(int &a, int &b)
  13. {
  14. int temp = a;
  15. a = b;
  16. b = temp;
  17. cout <<"swap2 "<< "a = " << a << " "
  18. << "b = " << b << endl;
  19. return;
  20. }
  21. // 地址传递
  22. void swap3(int *a, int *b)
  23. {
  24. int temp = *a;
  25. *a = *b;
  26. *b = temp;
  27. cout <<"swap2 "<< "a = " << *a << " "
  28. << "b = " << *b << endl;
  29. }
  30. int main()
  31. {
  32. int a=1,b=10;
  33. cout << a << " " << b << endl;
  34. swap1(a,b);
  35. cout << "swap1 "<<a << " " << b << endl;
  36. cout << a << " " << b << endl;
  37. swap2(a, b);
  38. cout <<"swap2 "<< a << " " << b << endl;
  39. swap3(&a, &b);
  40. cout <<"swap3 "<< a << " " << b << endl;
  41. return 0;
  42. }
  43. 1 10
  44. swap1 a = 10 b = 1
  45. swap1 1 10
  46. 1 10
  47. swap2 a = 10 b = 1
  48. swap2 10 1

Swap1中a,b的交换,形参不会改变实参的数值;Swap2中的a,b的交换,由于变量的引用,形参会改变实参的数值,与地址传递一致。

对于指针变量也有引用的使用,故若要在调用的函数中改变指针变量需要使用引用:

void CreateTree(BTNode *root) 是传值调用,这样原 root 的值是不能被改变的。形参是实参的一个copy。

void CreateTree(BTNode *&root) 是引用方式调用,若函数中 root指针进行改变,如生成左右孩子 , 那么原root也会改变。

函数返回引用

返回一个引用,则返回一个指向返回值的隐式指针。这样函数就可以放在赋值语句的左边。

当返回一个引用时,注意引用的对象不可以超过作用域,所以返回一个局部变量的引用时不合法的。但是可以返回一个对静态变量的引用。
  1. int& func(){
  2. int q;
  3. return q; // 错误
  4. // warning: reference to local variable 'i' returned [-Wreturn-local-addr]
  5. static int x;
  6. return x;
  7. }
  8. int main()
  9. {
  10. int &a = func();
  11. func() = 100; // ==> x = 100
  12. }