【C/C++】指针常量、常量指针、指向常量的常指针

2023-09-20 17:40:12

1.概念

首先明确这几个术语的具体含义:

  1. 指针常量(常指针):英语为:const pointer,即指针自己是常量
  2. 常量指针:英语为:pointer to a constant,即不能通过该指针去修改目标的指针
  3. 指向常量的常指针:英语为:a constant pointer to a constant,指针自己既是常量,也不能通过该指针去修改目标的指针

从英语可以很快速的理解这几个术语的含义,但是由于翻译的问题,就导致大家在初学 C++ 时会很晕头转向,被这几个概念搞的摸不清头脑
同样由于翻译的问题,还存在下面这组术语:

  1. 常量指针:指针自己是常量,这一版翻译主要强调的是指针自己是常量
  2. 指向常量的指针:即不能通过该指针去修改目标的指针,这一组的中文名可以见名思意,一目了然
  3. 指向常量的常量指针:指针自己既是常量,也不能通过该指针去修改目标的指针

而第二组的翻译和第一组的翻译在常量指针的位置刚好出现了两种截然不同的结果,或许这就是很多人在网上搜文章时感觉都不是很统一的原因吧,一部分文章按照第一组翻译去解释意思,另一部分文章按照第二组去解释就会导致看下来更加的晕头转向了

防止读者产生误会,我会在后续使用英语名来代替中文名,另外读者不用过分纠结中文名字,只需要能够分辨清楚 const pointerpointer to a constant 的定义方法与用法即可

2. const pointer

const pointer 意为指针自己是常量,所以无法更改指针的指向,并且一定要对指针进行初始化
定义方法如下:

 int a=1;
 int *const p1=&a;

const 放在 * 后面,强调修饰的是 p1 ,所以 p1 是常量,这样有助于读者更好的理解

3. pointer to a constant

pointer to a constant 意为指向常量的指针,指针本身是可以变化的,而且指针可以指向变量也可以指向常量,唯一不行的是通过指针去修改变/常量的值
定义方法如下:

const int *p1;

或者

int const *p1;

const 放在 * 前面,强调修饰的是 *p1 ,所以 *p1 是常量,这样有助于读者更好的理解
pointer to a constant 不要求进行初始化,因为指针本身还是一个变量,只有常量才会要求必须进行初始化
下面的表格给出了 pointer to a constantt 和被指对象的类型的兼容性,表格中所有指针均可以重新指向别的对象

pointer to a constant(指向常量的指针)poiner(普通指针)
constant(常量)×
variable(变量)

下面来逐一分析表格中的情况:

3.1 (pointer to a constant)-constant

对应下列的代码:

const int a=1;
const int *p1=&a;

该代码定义了一个常量 a ,并且将指针 p1 指向了常量 a,常量 a 不可以被任何方式进行修改

3.2 poiner-constant

假设下列的语句是合法的(下列语句是错误的):

 const int a=1;
 int *p1=&a;

那么就可以通过 *p1 来修改常量 a 的值,这与常量的概念不符,故不可以让普通指针指向常量

3.3 (pointer to a constant)-variable

对应下列的代码:

int a=1;
const int *p1=&a;

该代码定义了一个常量 a ,并且将指针 p1 指向了变量 a,变量 a 可以被直接修改,但是不可以通过 *p1 的方式对 a 进行修改

3.4 poiner-variable

对应下列的代码:

int a=1;
int *p1=&a;

该代码定义了一个常量 a ,并且将指针 p1 指向了变量 a,变量 a 可以被直接或者使用 *p1 修改

3.5 多层级关系时的兼容

这里先明确一个概念:在上述的代码中,只是涉及到了一层间接关系,即指针指向的是基本数据类型(不是指针),而在多层间接关系中,上述的部分规则将会不再适用
例如下面的代码在一层间接关系中是正确的:

int a=1;
const int *p1=&a;

pointer to a constant 可以与变量进行兼容,只是不能通过指针修改变量
而在二层间接关系时,这样的代码就会失效:

int a=1;
int *p2 = &a;
const int **p3 = &p2;

pointer to a constant 不能和普通指针兼容,若要使 p3 获得 p2 的地址,可以做如下的改动:

int a=1;
int *p2 = &a;
int **p3 = &p2;

或者

int a=1;
const int *p2 = &a;
const int **p3 = &p2;

在涉及到多层间接关系时,不允许 constnon-const 进行混用

3.6 用处

在进行函数调用时,若传参是数组,由于传递的时数组首地址,则可能调用函数时修改了原数组的内容,所以可以在定义函数时,声明 pointer to a constant 的形参,来防止函数内部修改数组,例如:

#include <iostream>
using namespace std;
int add(const int *begin,const int *end){
    int sum=0;
    for(;begin!=end;begin++)
        sum+=(*begin);
    return sum;
}
int main(){
    int arr[5]{1,2,30};
    cout<<add(arr,arr+5);
    return 0;
}

定义 add 函数时,形参声明为 pointer to const 防止对数组元素进行修改,同时还带来一个好处:不管入参是否为常量数组,它都可以进行接收,例如在主函数中,把 arr 改为 const 修饰,程序也可以运行,而如果是普通指针用作形参,则不能接收常量数组

4. a constant pointer to a constant

a constant pointer to a constant 含义为:指针的指向不可以改变,指针可以指向变量也可以指向常量,但是不能通过指针去修改变/常量的值,它的性质就像是 const pointerpointer to const 的结合体
定义方法如下:

int a=1;
const int *const p1=&a;

或者

int a=1;
int const*const p1=&a;
更多推荐

spring seccurity OAuth 2.0授权服务器工作流程

一、客户端配置:在configure(ClientDetailsServiceConfigurerclients)方法中,配置了一个客户端,包括客户端标识符、客户端秘密、授权类型、授权范围和令牌有效期等信息。这个客户端表示某个应用程序或服务,它将向授权服务器请求访问令牌。二、请求授权码:客户端应用程序首先将用户重定向到

文件包含漏洞

一、文件包含函数:将外部文件的内容引入当前环境:#include<stdio.h>includerequireinclude_oncerequire_oncehightlight_fileshow_sourcereadfilefile_get_contentsfopenfilephp文件包含函数:<?phpinclud

【搭建私人图床】本地PHP搭建简单Imagewheel云图床,在外远程访问

文章目录1.前言2.Imagewheel网站搭建2.1.Imagewheel下载和安装2.2.Imagewheel网页测试2.3.cpolar的安装和注册3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道(云端设置)3.3.Cpolar稳定隧道(本地设置)4.公网访问测试5.结语1.前言云存储

分享!JetBrains IDE中的GitLab支持

GitLab是流行的基于git的软件开发和部署平台之一,虽然很长一段时间以来,所有基本git操作都已经可以通过GitLab实现,但GitLab集成仍是JetBrains社区的一大最热门请求。为此,JetBrains团队今年与GitLab联手提供了这种类型的集成。JetBrains官方认为此类集成包括的各种功能可能会影响

springboot实现webSocket服务端和客户端demo

1:pom导入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.2.7.RELEASE</version></dependen

网站降权的康复办法(详解百度SEO数据分析)

随着搜索引擎算法的不断升级,很多网站在SEO优化过程中遭遇到降权的情况。如果您的网站也遭遇到了类似的问题,不必惊慌失措。本文将为您详细介绍网站降权恢复的方法,包括百度SEO数据分析、网站收录少的5个原因、网站被降权的6个因素以及百度SEO提升排名的4个方法。蘑菇号www.mooogu.cn首先,要想恢复网站降权,我们需

Rust踩雷笔记(7)——两个链表题例子初识裸指针

目录leetcode234leetcode19leetcode234题目在这https://leetcode.cn/problems/palindrome-linked-list/,leetcode234的回文链表,思路很简单,就是fast和slow两个指针,fast一次移动两个、slow一次一个,最后slow指向的链

【Linux系统编程】通过系统调用获取进程标识符 及 创建子进程(fork)

文章目录1.通过系统调用获取进程标示符(PID)1.1进程id(PID)1.2父进程id(PPID)2.bash也是一个进程3.通过系统调用创建进程-fork初识3.1批量化注释3.2取消注释3.3fork创建子进程3.4fork的返回值3.5fork之后通常要用if进行分流3.6父子进程代码共享,数据写时拷贝(实现相

手机号码携号转网API接口,轻松实现用户号码流转

携号转网是指用户可以将自己的手机号码从原来的运营商转移到其他运营商,以更好的服务、更低的资费和更多的优惠来吸引用户。而手机号码携号转网API接口,则是让开发者可以方便地实现用户号码流转的工具,下面就来介绍一下如何使用手机号码携号转网API接口。一、API接口简介手机号码携号转网API接口是指一个提供手机号码携号转网服务

GitHub 曝出漏洞,或导致 4000 多个存储库遭受劫持攻击

TheHackerNews网站披露,安全研究员发现GitHub中存在一个新安全漏洞,该漏洞可能导致数千个存储库面临劫持攻击的风险。据悉,在2023年3月1日漏洞披露后,微软旗下的代码托管平台已于2023年9月1日解决了安全漏洞问题。Checkmarx安全研究员EladRapoport在与TheHackerNews分享的

mysql向数据库中添加数据

要向MySQL数据库中添加数据,您可以使用INSERTINTO语句。以下是一些基本步骤和示例代码来添加数据:连接到数据库:首先,您需要使用MySQL客户端或编程语言中的MySQL连接库连接到您的数据库。编写INSERT语句:创建一个INSERTINTO语句,指定要插入数据的表名和要插入的数据列以及其值。语法如下:INS

热文推荐