C++ 指针使用时注意的问题(区别于引用)

指针(pointer)本身就是一个变量,其值是另一个变量的地址

说到指针,就涉及到指针的两个运算符(&,*):

  • 取地址运算符 && 是一元运算符,返回操作数的内存地址。例如,如果 val 是一个整型变量,则 &val 是它的地址。返回的结果是一个地址。
  • 间接寻址运算符 *,它是 & 运算符的补充。* 也是一元运算符,返回操作数所指定地址的变量的值。返回的结果五花八门,*p 类型是该指针 p 指向的类型。
  • 运算时都是从右往左顺序进行的。
int a = 12;  
int b;  
int *p;  
int **ptr;  

p = &a;     // &a 返回变量 a 的地址。p 是指针类型的变量,存储的是(指向)变量 a 的地址
*p = 24;    // 访问指针 p 所指向地址的内存空间,也就是 *p 就是访问变量 a
ptr = &p;   // &p的结果是个指针类型变量的地址,也就是说指针 ptr 指向指针变量 p 的地址
*ptr = &b;  // 访问指针 ptr 所指向地址的内存空间,也就是访问指针 p,令指针 p 指向变量 b 的地址
**ptr = 34; // *ptr的结果是 ptr 所指向的东西,在这里是指针 p,对这个指针再做一次 * 运算,结果就是指针 p 所指向的东西,即访问整型变量 b。

指针定义应注意的问题

在下文中,“对象”指的是能存储数据并具有某种数据类型的内存空间,并不严格区分是类还是内置类型。

(1)指针无须在定义时赋初值。

但是与其他内置类型一样,在块作用域内定义的指针如果没有初始化,也将拥有一个不确定的值(未定义的值,undefined)。

使用未经初始化的指针是引发运行时错误的一大原因:

在大多数编译器环境下,如果使用了未经初始化的指针,则该指针所占内存空间的当前内容将被看做一个地址值。访问该指针,相当于去访问一个本不存在的位置上本不存在的对象。糟糕的是,如果指针所占内存空间中恰好有内容,而这些内容又被当做了某个地址,我们就很难分清它到底是合法的还是非法的了。

因此建议初始化所有的指针,如果实在不清楚指针应该指向何处,就把它初始化为 nullptr 或者 0NULL 指针的值为 0,这样程序就能检测并知道它有没有指向任何具体的对象了。

(2)在指针的生命周期内它可以先后指向几个不同的对象。

指针和引用都能提供对其他对象的间接访问,然而在具体实现细节上二者有很大不同,其中最重要的一点就是引用本身并非一个对象,而指针本身就是一个对象:

  • 一旦定义了引用,就无法令其在绑定到另外的对象,之后每次使用这个引用都是访问它最终绑定的那个对象;
  • 指针和它存放的地址之间就没有这种限制了,和其他变量一样,给指针赋值就是令它存放一个新的地址,从而指向一个新的对象。

一旦定义了引用,就无法令其再绑定到另外的对象。

(3)指针的类型要和它所指向的对象严格匹配。

因为在声明语句中指针的类型实际上被用于指定它所指向对象的类型,所以二者必须匹配。如果指针指向了一个其他类型的对象,对该对象的操作将发生错误。

double dval;
double &pd = $dval;         // 正确:初始值是 double 型对象的地址
double *pd2 = pd;           // 正确:初始值是指向 double 对象的指针

int *pi = pd;               // 错误:指针 pi 的类型和 pd 的类型不匹配 
pi = &dval;                 // 错误:试图把 double 型对象的地址赋给 int 型指针

但也有两个例外情况:

  • 允许令一个指向常量的指针指向一个非常量的对象。
  • 存在继承关系的类,可以讲基类的指针或引用绑定到派生类对象上。

(4)指针本身就是一个对象,存在指针的指针和指针的引用

一般来说,声明符中修饰符的个数并没有限制。当有多个修饰符连写在一起时,按照其逻辑关系详加解释即可。

以指针为例,指针是内存中的对象,像其他对象一样也有自己的地址,因此允许把指针的地址再放到另一个指针当中。

int ival = 1024;            
int *pi = &ival;            // pi 指向一个 int 型的数
int **ppi = π            // ppi 指向一个 int 型的指针

此处 pi 是指向 int 型数的指针,而 ppi 是指向 int 型指针的指针,下图描述了它们之间的关系:

在这里插入图片描述

int i = 42;
int *p;                     // p 是一个 int 型指针
int *&r = p;                // r 是一个对指针 p 的引用

                // 对 r 进行操作与对 p 进行操作是一样的
r = &i;         // r 引用了一个指针,因此给 r 赋值 &i 就是令 p 指向 i
*r = 0;         // 解引用 r 得到 i,也就是 p 指向的对象,将 i 的值改为 0

但是因为引用不是一个对象,只是一个别名,因此不能定义指向引用的指针或者指向引用的引用。

(5)允许在一条定义多个指针变量,每个变量前面都必须有符 ∗ *

int *ip1, *ip2;         // 都是指向 int 型对象的指针
int *ip1, ip2           // ip1 为 int 指针类型,ip2为 int 型
double dp, *dp2;        // dp2 是指向 double 型对象的指针,dp 是 double 型对象

int* ip, i, &r = i;     // 指针类型,int类型,引用类型
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值