C/C++中指针与引用详细说明

1.说明

  • 指针是一个实体,需要分配内存空间。引用只是变量的别名,
    不需要分配内存空间。
  • 引用在定义的时候必须进行初始化,并且不能够改变。指针在
    定义的时候不一定要初始化,并且指向的空间可变。引用的初始
    值不能为NULL。
  • 有多级指针,但是没有多级引用,只能有一级引用。
  • 指针和引用的自增运算结果不一样。指针自增运算是指向下一
    个空间,引用自增运算是引用的变量值加1。
  • sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof
    指针得到的是指针本身的大小。
  • 引用访问一个变量是直接访问,而指针访问一个变量是间接访
    问。
  • 使用指针前最好做类型检查,防止野指针的出现;
  • 作为参数时也不同,传指针的实质是传值,传递的值是指针的
    地址;传引用的实质是传地址,传递的是变量的地址;
  • 引用底层是通过指针实现的。

2.分析

2.1 指针和引用的本质

指针是存放内存地址的一种变量,特殊的地方就在它存放的是内存地址。因此,指针的大小不会像其他变量一样变化,只跟当前平台相关——不同平台内存地址的范围是不一样的,32位平台下,内存最大为4GB,因此只需要32bit就可以存下,所以sizeof(pointer)的大小是4字节。64位平台下,32位就不够用了,要想内存地址能够都一一表示,就需要64bit(但是目前应该没有这么大的内存吧?),因此sizeof(pointer)是8。
引用的本质是“变量的别名”,就是给变量又重新起了一个名字,既然是“别名”,那么就一定要有本体。

2.2 声明和初始化区别

指针指向的是一个内存地址, 因此可以指向一块为0x00000000的地址,声明时可以暂时不初始化(不推荐),即pointer = NULL;
引用是变量的别名,别名就一定对应着一个“本名”,因此必须在声明时就初始化,且不能初始化为空。

2.3 使用区别

  • 根据声明和初始化时二者的区别,指针在声明周期内随时可能会为Null,所以使用时一定要做检查,防止出现空指针、野指针的情况;而引用则不用再操这个心,只要初始化了,在哪里都可以直接使用,再也不用担心它会不会为空什么的了。
  • 指针因为自己存的是一个内存地址,既然可以存初始化(或者赋值)的地址,那么在指针生命周期内就可以存其他的地址,只要你是同一类型(不同类型这个对应的类型偏移不一样)的变量,对于指针都OK。

引用作为一个变量AA的别名,在它的整个生命周期内,它只能“从一而终”,始终是第一次初始化它的那个变量的别名,在这期间任何对它的操作,都等同于对变量AA的操作。

3.举例说明

#include <iostream>
#include <string>
 

void Test1();

 
int main( )
{

   
   Test1();
   return 0;

}


void Test1()
{
   /** 指针和引用的例子 **/

  std::string s1 = "华为";
  std::string s2 = "小米";
  std::string s3 = "OPPO";
  std::string s4 = "三星";

  /** 指针可以初始化为空 **/
  std::string *p_Str = NULL;
  /** 引用一开始必须初始化 **/
  std::string& r_Str = s1;

  p_Str = &s2;
  std::cout<<"指针"<<*p_Str<<std::endl; /** 小米 **/
  std::cout<<"引用"<<r_Str<<std::endl; /** 华为 **/
  std::cout<<std::endl;
  std::cout<<"*********分别修改指针和引用***********"<<std::endl;
  /** 分别修改指针和引用 **/
  r_Str = s3; /** 试图让r_Str为s3的别名 **/
  p_Str = &s4; /** p_Str重新指向了s4 **/
  
  std::cout<<"指针"<<*p_Str<<std::endl; /** 三星 **/
  std::cout<<"引用"<<r_Str<<std::endl;  /** OPPO **/
  std::cout<<std::endl;
  std::cout<<"*********查看刚刚的修改对最初初始化的影响***********"<<std::endl;
  /** 貌似成功了,都按照意图修改了,但是,稍等 **/
  std::cout<<"it is s1"<<s1<<std::endl; /** OPPO !!!注意 !!! **/
  std::cout<<"it is s2"<<s2<<std::endl; /** 小米 **/
  std::cout<<"it is s3"<<s3<<std::endl; /** OPPO **/
  std::cout<<"it is s4"<<s4<<std::endl; /** 三星 **/

  /** 
  发现s1 "华为" 被变成了和s3一样的"OPPO",这也说明了任何对引用的操作都等同于操作原先的变量本身
  相比较之下,指针就自由度很高了,想指向谁就指向谁,并不会影响任何之前指向过的变量
  惊不惊喜,意不意外 :)
  **/
}

输出结果:

指针小米
引用华为

*********分别修改指针和引用***********
指针三星
引用OPPO

*********查看刚刚的修改对最初初始化的影响***********
it is s1OPPO
it is s2小米
it is s3OPPO
it is s4三星

总结

一个不大恰当的比喻是,指针就像是一个可以(注意是可以,但未必一定)到处沾花惹草(可以随时指向任意地址)的“渣男”;而引用则像是一个只能“从一(谁初始化就跟谁)而终”的“老实人”。

另外,根据Scott Meyers在《More Effective C++》上所讲,只有当你确定需要一开始就初始化,并且不需要再指向其他类型时 使用引用,否则你都应该使用指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值