理清C++常量指针和指针常量这团乱麻

时间:2022-09-09 08:40:43

写在前面:

与其说C++中的常量指针和指针常量是一块很有嚼头的语法糖,不如说它是一块相当难啃的骨头。其实本来没什么,这无非是const int *p与int* const p的区别, 但一涉及到起名字,特别是给他们戴上“常量指针”和“指针常量”的中文帽子,由于作者和译者(针对外文书)的不同,就出现了“张冠李戴”和“李冠张戴”的乱像,不知道谁是谁了,弄得人一头雾水,尤其是对于初学者。本文的目的就是针对这一细节,为大家将两者理清楚,同时说明在使用上的区别。

注意:1.const int *p也可写成int const *p,即C++中const int和int const无区别,这使得本来就很乱的局面更加麻烦,本文中我只使用const int,以后不再说明。

2.如果您讨厌啰嗦,只想学“干货”,您可以直接跳到“安能辨我是雄雌——判断方法”一节(在下技术有限,就不设置页面内跳转了)。

在理清楚之前,让 我们先简单看看当前“乱象丛生”的现状吧。

一、const遇上指针——一团乱麻

同样的问题,相反的解释

1.标新立异的少数派

C++ Primer第五版的提法可谓与其它C++书籍背道而驰,它的提

常量指针——int* const p

指向常量的指针——const int *p

在英文版中,int* const p被称为const pointer,于是中文版将其译为常量指针;而const int *p被称为pointer to const,但对应的中文版并未将其译为指针常量,而是译为指向常量的指针。

无独有偶,我们国内的书籍《零起点学通C++》(范磊 著 清华大学出版社 2010年版)的提法和C++ Primer完全一致,将int* const p称为常量指针,而将const int *p称为指向常量的指针。

2.一边倒的大众说辞

更广为流传的提法是

常量指针——const int *p

指针常量——int* const p

明确写有“常量指针”和“指针常量”的书籍在下就见过一本——《C++面向对象程序设计》(郭有强 著 清华大学出版社 2009年版)(从出版年上我们可以大胆推测,相对较老的书会这样提)。更多的书籍的做法是——将int* const p称为指针常量,将const int *p称为指向常量的指针。(可见问题的关键在于int* const p,有的书中将其称为常量指针,如1,有的书中将其称为指针常量,如2)

这里的“一边倒”更主要的是针对网络而言。如果您百度“常量指针和指针常量”,将会看到几乎所有的材料中都采用了2中的提法。如果一个初学者在解决“常量指针和指针常量”的困惑时首先选择了网络途径,那么2的提法应该在他的脑海里根深蒂固了吧。

如果您已经接受了2中的提法,建议您将“常量指针”扩展为“指向常量的指针”,将“指针常量”扩展为“该指针是常量”来帮助您记忆和区别两者的本质。

作者们的拯救

大概一些IT教育者和从业者们也注意到了这一问题,近年来的一些书籍作者们开始用自己的方式来纠正,让我们来看看他们是怎么做的。

1.这样的改变好吗?

《C++程序设计基础》(管建和 著 清华大学出版社 2013年版)中将const int *p称为“常量化指针目标表达式”,而将int* const p称为“常量化指针变量”,试问,这么长的名字,能不能记住?记住了,能不能搞清楚?

2.两个弄不清,干脆叫一个

比较著名的外文书籍《C++高级编程》(这里就中文第二版讲)中在“const指针”的标题下同时介绍了const int *p和int* const p,而没有给他们具体起名字。

在国内,《新标准C++程序设计教程》(郭炜 著 清华大学出版社 2012年版)将const int *p称为常量指针,而在介绍int* const p时写道“还有一种常量指针”。

但这样做仍然不能称之为行之有效,因为这样并没有通过名字将两者从本质上区分,同时“不同的事物,同一个名字”也不便于交流。

3.一种值得推荐的命名法

《C++程序设计教程》(方超昆 著 北京邮电大学出版社 2009年版)和《C++从入门到精通》(人民邮电出版社 2015年版)是这样提的

指向常量的指针变量——const int* p

指向变量的指针常量——int* const p

指向常量的指针常量——const int* const p   //后面会详细说到

这样,谁常谁变就一目了然了,而且名字反应了本质。从第一本书的出版年可以看出,其实这样比较清晰的命名方式好几年前就有了,但可惜的是,直到现在,在众多的C++书籍中,这般清晰的命名方式也并不多见。

在下的用意

一定会有人说:“你说了这么多,并没有给我们带来什么实质性的知识。”在下不反对,其实在下在这一部分的开头已经清醒过大家,可以略过。在下写这部分的用意有四:

1.向读者介绍一下现状和常见的提法。

2.告诉读者该问题上存在的不一致现象,当读者阅读不同的书籍时遇到不一致,不要过于困惑。

3.劝读者不要记忆网上的“常量指针”和“指针常量”,因为这样的命名并不好,许多书籍上也并没有同时提到这两者。

4.表达一下自己希望C++的相关命名实现术语化、标准化、大一统的愿望,尽管在下知道这一点很难实现。

在下怎么看

1.不要使用“常量指针”和“指针常量”,特别是后者,因为它连“表述对象是指针”这层意思都没有清晰地表达出来。

2.建议采用“一种值得推荐的命名法”下的名称来记忆。

3.或者采用在下的建议。现在说明在下的提法

指向常量的指针——const int *p

本身是常量的指针——int* const p

所指和本身都是常量的指针——const int* const p

这里采用“定语+主体”的结构,主体“指针”很好地表现了所描述对象是指针这一本质,而定语部分则描述了特性,同时也将“自己”和“他人”区别开,整体通俗易懂。(在下一直认为,有时一个高大上的名称就是故作高深,而通俗易懂本身就是一种真正的高大上。面向初学者,把话说明白,一直是在下文章的宗旨与追求。)唯一的不足可能是名称有点长,但在下相信,只要足够通俗易懂,长不是障碍。

从现在开始,我们在后面的讲述中将一直采用这种提法。

二、安能辨我是雄雌——判断方法

相信有些初学者会有这样的困惑:单提名字知道怎么回事,但一看到代码就不知道叫什么名字了,也就无法想起代码的语法特性。这里,在下给大家介绍一种简单易用的判断方法,一看代码就能分析出语法特性。

相信有些读者看到过所谓的“从右往左读”的办法,在下接下来要说的方法和“从右往左读”本质上一样,只不过无论是认知还是操作上都更加简单(起码在下认为是这样,这里就不谦虚了)。方法表述如下:

先找到*,然后看*的两边,右边是对指针p本身的限定,左边是对p所指向的东西的限定。

注:本文中我们将p的所指笼统地称为“东西”。

例如

1.const int *p

*的右边没有限定成分,表明p就是我们熟悉的普通指针,p的内容(即值,也就是它指向的东西的地址)是可以改变的;*的左边是const int,表明p指向的东西是一个const的int,我们不能通过p来修改这个int,因为它是const的。(关于“不能通过p来修改”,我们后边还会详细解释)

2.int* const p

*的右边是const,表明p本身是const的,我们不能对p的内容进行修改(例如++p;是不可以的),*的左边是int,即p指向的东西是普通的int,我们可以通过p来修改它(例如*p=100;是可以的)。

3.const int* const p

*的右边是const,表明指针p本身是const的,*的左边是const int,表明p指向的int也是const的。即这种情况下,p本身不能修改,同时也不能通过p修改它所指向的那个int。

三、天生我材必有用——语法特性

其实在讲判断方法的时候,已经涉及到了各自的语法特性。这里再针对一些细节深入说一下。

1.const int *p

就是所谓的“指向常量的指针”。这里注意,所谓“指向常量”只是这个指针的“一厢情愿”,只是一种效果上的等价。事实上,const int *p=&a;a既可以是常量(const int a=10;)又可以是变量(int a=10;),但p一厢情愿地认为它所指的就是一个常量,所以它不允许通过自己来修改所指,这就造成一种效果上的等价——从p的角度看,它所指的“的确”是常量。所以,对“指向常量的指针”的最佳理解应为:我们不能通过该指针修改它所指向的东西(常量或者变量)。

注意,const int *p=&a;只是说不能通过p来修改a,如果a本身不是const的,通过其它方式修改a自然是可以的(例如直接++a)。

另外一点,由于p本身只是一个普通的指针,所以允许在声明时不初始化。但需要注意的是,我们只是说可以,但并不提倡这样做。在任何时候都不应该让指针无所指,如果在声明一个指针时还不知道让它指向谁,就先将其初始化为nullptr或NULL(nullptr是C++11新特性,用它比用NULL更安全些,这里不详细介绍)。

2.int* const p

就是所谓的“本身是常量的指针”。关于“p本身不能修改但可以通过p修改其所指”这一点,我们在讲判断方法时已经说过,这里主要再说一下p的初始化。

由于p本身是const的,所以在编译的时候必须知道p的值(即p所指向的东西的地址),所以在声明p的同时必须初始化p。但要注意,对于 int* const p=&a,我们只要求a的地址是确定的,但a的值可以不确定。比如下面的代码是可行的

理清C++常量指针和指针常量这团乱麻
#include<iostream>

using namespace std;

int GetData(int num)
{
return num;
} int main()
{
int a;
cin >> a;
int b = GetData(a);
int* const p = &b;
cout << *p << endl;
return 0;
}
理清C++常量指针和指针常量这团乱麻

由于声明了int b,所以b的地址在编译时是确定的,但很显然,b的值只要在程序运行时才能确定。

另外注意,用nullptr或NULL初始化int* const p没有问题,因为nullptr和NULL都代表有效地址。

3.const int* const p

就是所谓的“所指和本身都是常量的指针”。它的语法特性就是前两者的结合,这里不再赘述。

四、番外篇——说说引用和const引用

文章至此本该结束了,但就C++而言,谈到了指针,似乎自然应该再谈谈引用。于是,在下接着再来简单说说引用和const引用。所谓“简单说说”,是指在下只是做一个简明扼要的介绍,对一些原理和细节不做深入探讨。为什么要在这里说?因为我们的讲述要会用到上面的概念。另外还要注意,我们这里只讨论左值引用,即大家所熟悉的一般引用,对于C++11新特性右值引用,不在讨论之列。

相信大家都知道引用的这些特性

1.如果一个引用和一个东西(这里再次使用“东西”这个词)绑定,那么它就永远只能是这个东西的“别名”,不能再说“其他人”的“别名”,即引用本身不能修改。但是,我们可以通过引用来修改它所引用的东西的值。

2.引用声明时必须同时初始化 ,且必须用左值初始化。(左值:就是可以用&求地址的量,换言之,就是有确定地址的量,而不是所谓的临时量)

对这些特性大家是不是似曾相识呢?没错,这些特性和“本身是常量的指针”(int* const p)的特性一样。事实上,我们完全可以借用“本身是常量的指针”来理解甚至定义引用:

引用是一个指向不可变的、被编译器自动解引用的指针,即,引用是一个被编译器自动解引用的“本身是常量的指针”。

看下面的代码

int a = 10;
int &ra = a;
ra = 11;

在上面的代码中,编译器将int &ra=a转化为int* const ra=&a,而将ra=11转化为*ra=11,将ra自动转化为*ra的过程,就是上面定义中所说的“自动解引用”。

那么,什么是const引用(即我们说的常量引用,但我希望大家称其为const引用而不是常量引用)呢?很显然,const int &ra=a就相当于const int* const ra=&a了。相信通过前面的讲解,这里不用在下多说了。

后记:

在下能力有限,尽管尽最大努力做到严谨,但错误疏漏之处仍在所难免,恳请大家批评指正。您的帮助,就是在下前进的不竭动力。

理清C++常量指针和指针常量这团乱麻的更多相关文章

  1. C&plus;&plus;基础之二:常量指针和指针常量

    1.常量指针 定义:具有只能够读取内存中数据,却不能够修改内存中数据的属性的指针,称为指向常量的指针,简称常量指针. 声明:const int * p; 注:可以将一个常量的地址赋值给一个对应类型的常 ...

  2. 【转】const int &ast;p和int &ast; const p的区别(常量指针与指向常量的指针)

    [转]作者:xwdreamer   出处:http://www.cnblogs.com/xwdreamer 对于指针和常量,有以下三种形式都是正确的: const char * myPtr = &am ...

  3. C&plus;&plus;引用和const引用、常量指针、指针常量

    1.引用.常量引用 引用主要被用做函数的形式参数--通常将类对象传递给一个函数. 引用在内部存放的是一个对象的地址,它是该对象的别名.引用不占用内存,因为取地址引用的值和被引用变量的地址相同.但是ob ...

  4. C&sol;C&plus;&plus;中的常量指针与指针常量&lpar;转&rpar;

    常量指针 常量指针是指向常量的指针,指针指向的内存地址的内容是不可修改的. 常量指针定义“const int *p=&a;”告诉编译器,*p是常量,不能将*p作为左值进行操作.但这里的指针p还 ...

  5. C语言学习笔记 &lpar;001&rpar; - 常量指针与指针常量的区别(转帖)

    三个名词虽然非常绕嘴,不过说的非常准确.用中国话的语义分析就可以很方便地把三个概念区分开. 一) 常量指针. 常量是形容词,指针是名词,以指针为中心的一个偏正结构短语.这样看,常量指针本质是指针,常量 ...

  6. 数组&sol;指针&sol;const&sol;字符串常量的使用传值问题

    #include<stdio.h> #include<string.h> int main() { ] = "abcd"; //常指针a指向字符串常量&qu ...

  7. c&plus;&plus;中指针常量,常指针,指向常量的常指针区分

    const char * myPtr = &char_A;//指向常量的指针 char * const myPtr = &char_A;//常量的指针 const char * con ...

  8. C&plus;&plus; const 常量和常指针

    常量,该指针所指向的值为只读 ; const int * p = &a; 常指针,该指针的值为只读,不可再指向其他地址 const * const p = &a; 常值,常指针 con ...

  9. 常量指针-指向常量的指针&comma;指针常量-指针本身是常量&comma;常量-不能更改值的常量&comma;数组指针-是指针int &lpar;&ast;p&rpar;&lbrack;n&rsqb; 指针数组-是数组int &ast;p&lbrack;n&rsqb;

    1.常量指针 定义:具有只能够读取内存中数据,却不能够修改内存中数据的属性的指针,称为指向常量的指针,简称常量指针. 声明:const int * p; int const * p; 注:可以将一个常 ...

随机推荐

  1. c&plus;&plus;实现螺旋矩阵分析总结

    螺旋矩阵,是这么一个东西: 1   2   3 8   9   4 7   6   5 这是一个,n*n的矩阵,由外向里一次递增,一环一环,就好像一个螺旋一样.不难想象,如果n=5,那么应该是这样的: ...

  2. Eclipse 乱码解决方案(UTF8 -- GBK)

    UTF8 --> GBK;   GBK --> UTF8 eclipse的中文乱码问题,一般不外乎是由操作系统平台编码的不一致导致,如Linux中默认的中文字体编码问UTF8, 而Wind ...

  3. linux 常见操作指令

    1.ssh root@ip ssh 登录 2.ll ls 列出当文件夹下 所以文件 3. cd ./xx 进入 xx 文件夹 4. vim vi xxx 进入 xx文件的 编辑模式. i 开始编辑 e ...

  4. linux系统下python升级安装

    1.安装gcc gcc-c++ yum install -y gcc gcc-c++ #提前检查是否安装 2.下载python3.5.2安装包 cd /usr/local/src/ wget http ...

  5. mysql 5&period;7&period;10 下互为主备配置

    mysql安装方法这里就不在介绍,网上有很多教程 环境介绍: A主机: win2008_x64+mysql5.7.10 64位,ip192.168.7.180 B主机: win2008_x64+mys ...

  6. Cesium添加水面

    var viewer = new Cesium.Viewer('cesiumContainer');var waterPrimitive = new Cesium.Primitive({ //show ...

  7. Django - 权限(4)- queryset、二级菜单的默认显示、动态显示按钮权限

    一.queryset Queryset是django中构建的一种数据结构,ORM查询集往往是queryset数据类型,我们来进一步了解一下queryset的特点. 1.可切片 使用Python 的切片 ...

  8. 4&period;flume实战(一)

    需求:从指定网络端口采集数据输出到控制台 使用flume的关键就是写配置文件 a)配置source b)配置channel c)配置sink d)把以上三个组件串起来 我们看一下官网给的配置文件 # ...

  9. git use

    git init git init --bare  ''会将文档直接加上.git后缀 具体内容请渡 git add --all git commit -m 'label' git push --all ...

  10. &lbrack;Python3网络爬虫开发实战&rsqb; 2&period;4-会话和Cookies

    在浏览网站的过程中,我们经常会遇到需要登录的情况,有些页面只有登录之后才可以访问,而且登录之后可以连续访问很多次网站,但是有时候过一段时间就需要重新登录.还有一些网站,在打开浏览器时就自动登录了,而且 ...