当前位置: 首页 > article >正文

[通俗易懂C++]:指针和const

之前的文章有说过,使用指针我们可以改变指针指向的内容(通过给指针赋一个新的地址)或者改变被保存地址的值(通过给解引用指针赋一个新值):

int main()
{int x { 5 };  // 创建一个整数变量 x,初始值为 5int* ptr { &x }; // 创建一个指针 ptr,指向 x 的地址(非 const 指针)int y { 6 };  // 创建一个整数变量 y,初始值为 6ptr = &y;  // 将 ptr 指向 y 的地址,我们可以改变它指向的地址*ptr = 7;  // 通过指针修改 ptr 所指向地址的值,即将 y 的值改为 7return 0;  // 程序成功结束
}

那么,如果我们想指向的值是const呢?

int main()
{const int x { 5 }; // x 现在是常量,值为 5int* ptr { &x };   // 编译错误:不能将 const int* 转换为 int*,因为 x 是常量,不能修改它的值return 0;  // 程序正常结束
}

这段代码会出现编译错误,因为我们尝试将一个指向 const int 类型的指针赋值给一个普通的 int* 指针,C++ 中不允许这样做。具体原因是 const 修饰符确保该变量的值在程序运行期间不能被修改,而普通的 int* 指针允许修改所指向的内容,所以会发生类型不匹配。


指向常量值的指针

指向常量值的指针(有时简称为指向 const 的指针)是一个(非 const)指针,它指向一个常量值。声明指向常量值的指针时,只需要在指针的数据类型之前使用const关键字。

int main()
{const int x {5};const int* ptr = {&x};*ptr = 6; // 非法操作:不能更改const值return 0;
}

在上面的示例中, ptr 指向一个 const int 。因为被指向的数据类型是 const,所以指向的值不能被更改。

然而,因此指向常量的指针本身不是常量(而是它的指向是一个常量),所以,我们可以通过给指针赋值=一个新的地址来改变指针指向的内容。

image-20250222224723856

int main()
{const int x {5};const int* ptr = {&x}; // ptr指向一个值为const的int类型的变量地址const int y {6};ptr = &y; // 指向一个新的地址std::cout << ptr << '\n';std::cout << *ptr << '\n';return 0;
}

就像 const 引用一样,指向 const 的指针也可以指向非 const 变量。指向 const 的指针将所指向的值视为常量,不管该地址上的对象最初是否被定义为 const

有点绕口,看个例子助消化:

int main()
{int x{ 5 }; // 非 const 变量,x 的初始值为 5const int* ptr { &x }; // ptr 是一个指向 const int 的指针,指向 x*ptr = 6;  // 不允许:因为 ptr 指向的是 "const int",所以不能通过 ptr 修改值x = 6; // 允许:因为 x 是非 const 的,直接修改 x 的值是可以的return 0; // 程序结束
}
  • **int x{ 5 };**这里定义了一个非 const 变量 x,并将其初始化为 5。
  • const int* ptr { &x };:定义了一个指向 const int 类型的指针ptr,它指向变量 x 的地址。虽然 x 是一个非 const 变量,但指针 ptr 被声明为指向 const 类型的对象。这样,ptr 不能修改所指向的值。
  • ***ptr = 6;**这是一个编译错误。虽然 x 是非 const 的,但由于 ptr 是指向 const int 的指针,编译器禁止通过该指针修改 x 的值。这是因为 ptr 被声明为指向常量,所以它会将 x 视为常量
  • **x = 6;**这行代码是允许的,因为 x 是非 const 的,直接通过变量名 x 修改其值没有问题。指针的 const 属性只影响通过指针访问数据时的行为,而不是通过普通的变量名。

常量指针

基于上述这些理论不难想到,我们也可以使指针本身成为常量。这就是常量指针,该指针是指其地址初始化后不能再次被更改。和普通的常量定义的概念是一致的,不过是将这个概念用在了指针类型上。

声明一个常量指针,在指针声明中的星号后面使用const关键字即可:

int main()
{int x{ 5 };int* const ptr { &x }; //星号之后的const意味着这是const指针return 0;
}
  • 在上述情况下, ptr 是一个指向(非 const)int 值的 const 指针。

  • 就像一个普通的 const 变量一样,const 指针必须在定义时初始化,并且这个值不能通过赋值来改变:

int main()
{int x{ 5 }; // 创建一个整数变量 x,初始值为 5int y{ 6 }; // 创建一个整数变量 y,初始值为 6int* const ptr { &x }; // const 指针 ptr 被初始化为指向 x 的地址ptr = &y; // 错误:一旦初始化,const 指针就不能改变它指向的地址return 0; // 程序正常结束
}

然而,因为所指向的值是非 const 的,可以通过解引用 const 指针来更改所指向的值:

 int main()
{int x{ 5 };int* const ptr { &x }; *ptr = 6; return 0;
}

最后,可以通过在类型和星号之前和之后都是用const关键字来声明一个指常量值的常量指针:

int main()
{int value { 5 };const int* const ptr { &value }; // 指常量值的常量指针return 0;
}

一个指向常量值的常量指针不能改变其地址,也不能通过该指针改变它所指向的值。它只能解引用以获取它所指向的值。


小结一下

  • 一个非 const 指针(例如 int* ptr )可以被分配另一个地址以改变它所指向的内容。
  • 一个常量指针(例如 int* const ptr )始终指向同一个地址,并且这个地址不能更改。
  • 一个指向非 const 值的指针(例如 int* ptr )可以改变它所指向的值。这些指针不能指向 const 值。
  • 一个指向常量值的指针(例如 const int* ptr )在通过该指针访问时将值视为常量,因此不能更改它所指向的值。这些指针可以指向常量或非常量左值(但不能指向右值,因为右值没有地址)。

感谢阅读、欢迎指正!

相关文章:

[通俗易懂C++]:指针和const

之前的文章有说过,使用指针我们可以改变指针指向的内容(通过给指针赋一个新的地址)或者改变被保存地址的值(通过给解引用指针赋一个新值): int main() {int x { 5 }; // 创建一个整数变量 x&#xff0c;初始值为 5int* ptr { &x }; // 创建一个指针 ptr&#xff0c;指向 …...

大一高数(上)速成:导数和微分

目录 1.分段函数的可导性&#xff1a; 2.隐函数求导: 3.参数方程求导: 4.对数求导法: 5.函数的微分: 1.分段函数的可导性&#xff1a; 2.隐函数求导: 3.参数方程求导: 4.对数求导法: 5.函数的微分:...

使用 DeepSeek 和 Google Gemini 算命

目录 DeepSeek 调用Gemini 调用基础 PromptFAQ1. Gemini 返回失败2. DeepSeek 超时 DeepSeek 调用 由于 DeepSeek API 是兼容 openai 的&#xff0c;所以直接使用 openai 的 sdk 即可。 // Please install OpenAI SDK first: npm install openaiimport OpenAI from openai; i…...

京东cfe滑块 分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 headers {"accept&qu…...

list结构刨析与模拟实现

目录 1.引言 2.C模拟实现 2.1模拟实现结点 2.2模拟实现list前序 1&#xff09;构造函数 2&#xff09;push_back函数 2.3模拟实现迭代器 1&#xff09;iterator 构造函数和析构函数&#xff1a; *操作符重载函数&#xff1a; 前置/后置/--&#xff1a; /!操作符重载…...

react 踩坑记 too many re-renders.

报错信息&#xff1a; too many re-renders. React limits the number of randers to prevent an infinite loop. 需求 tabs只有特定标签页才展示某些按钮 button要用 传递函数引用方式 ()>{} *还有要注意子组件内loading触发 导致的重复渲染...

BGP分解实验·19——BGP选路原则之起源

当用不同的方式为BGP注入路由时&#xff0c;起源代码将标识路由的来源。 &#xff08;在BGP表中&#xff0c;Network为“i”&#xff0c;重分布是“&#xff1f;”&#xff09; 实验拓扑如下&#xff1a; R2上将来自IGP的路由10.3.3.3/32用network指令注入BGP;在R4上将来自I…...

二叉树中每个节点能到达的最远距离

一、题目描述 输入一个只包含0和1的字符串表示二叉树&#xff0c;输出每个节点能到达的最远距离&#xff0c;通过父节点的路径也要考虑。 比如输入"111110000010000", 输出[3,2,4,3,3,4]。 1A / \ 1B 1C / \ / \ 1D 1E 0 0 / \ /…...

单机上使用docker搭建minio集群

单机上使用docker搭建minio集群 1.集群安装1.1前提条件1.2步骤指南1.2.1安装 Docker 和 Docker Compose&#xff08;如果尚未安装&#xff09;1.2.2编写docker-compose文件1.2.3启动1.2.4访问 2.使用2.1 mc客户端安装2.2创建一个连接2.3简单使用下 这里在ubuntu上单机安装一个m…...

结构体简介

前言 这篇文章呢就给大家简单讲解一下什么是结构体&#xff0c;也让大家对结构体有一个较为清晰的了解&#xff0c;从而帮助同学们更好的掌握结构体。 结构体类型的声明 结构的声明 在声明结构体的类型是&#xff0c;先给大家拓展两个重要的关键字 typedef 和 struct. 拓展…...

家用路由器的WAN口和LAN口有什么区别

今时今日&#xff0c;移动终端盛行的时代&#xff0c;WIFI可以说是家家户户都有使用到的网络接入方式。那么路由器当然也就是家家户户都不可或缺的设备了。而路由器上的两个实现网络连接的基础接口 ——WAN 口和 LAN 口&#xff0c;到底有什么区别&#xff1f;它们的功能和作用…...

实操解决Navicat连接postgresql时出现‘datlastsysoid does not exist‘报错的问题

1 column “datlastsysoid“ does not exist2 Line1:SELECT DISTINCT datalastsysoid FROM pg_database问题分析 Postgres 15 从pg_database表中删除了 datlastsysoid 字段引发此错误。 决绝方案 解决方法1&#xff1a;升级navicat 解决方法2&#xff1a;降级pgsql 解决方…...

3分钟idea接入deepseek

DeepSeek简介 DeepSeek 是杭州深度求索人工智能基础技术研究有限公司开发的一系列大语言模型&#xff0c;背后是知名量化资管巨头幻方量化3。它专注于开发先进的大语言模型和相关技术&#xff0c;拥有多个版本的模型&#xff0c;如 DeepSeek-LLM、DeepSeek-V2、DeepSeek-V3 等&…...

树莓派理想二极管电路分析

如果 Vin Vout&#xff0c;比如说 5.0V&#xff0c;PNP 晶体管以当前的镜像配置偏置。晶体管 U14 的 Vb 将为 5-0.6 4.4V&#xff0c;镜像配置意味着 Vg 也将为 4.4V. Vgs 为4.4-5.0 -0.6V。mosfet 将处于关闭状态&#xff08;几乎打开&#xff09;。如果 Vout 略低于 Vin&a…...

关于在mac中配置Java系统环境变量

引言 在 macOS 上开发 Java 或 Flutter 应用时&#xff0c;正确配置环境变量是至关重要的。环境变量不仅能让系统找到开发工具的位置&#xff0c;还能简化命令行操作。本文将手把手教你从零开始安装 Java SDK&#xff0c;并详细配置环境变量&#xff0c;涵盖常见问题解决和优化…...

Unity贴图与模型相关知识

一、贴图 1.贴图的类型与形状 贴图类型 贴图形状 2.在Unity中可使用一张普通贴图来生成对应的法线贴图&#xff08;但并不规范&#xff09; 复制一张该贴图将复制后的贴图类型改为Normal Map 3.贴图的sRGB与Alpha sRGB&#xff1a;勾选此选项代表此贴图存储于Gamma空间中…...

Linux--进程(进程虚拟地址空间、页表、进程控制、实现简易shell)

一、进程虚拟地址空间 这里以kernel 2.6.32&#xff0c;32位平台为例。 1.空间布局 在 32 位系统中&#xff0c;虚拟地址空间大小为 4GB。其中&#xff1a; 内核空间&#xff1a;占据高地址的 1GB &#xff0c;用于操作系统内核运行&#xff0c;包含内核代码、内核数据等&am…...

中间件专栏之redis篇——redis基本原理、概念及其相关命令介绍

一、redis是什么 redis是remote dictionary service的简称&#xff0c;中文翻译为远程字典服务&#xff1b; redis是一种数据库&#xff0c;若按照类型来归类&#xff0c;则其可以被归入三个类型数据库&#xff0c;分别为&#xff1a;内存数据库、KV数据库、数据结构数据库&a…...

python使用httpx_sse调用sse流式接口对响应格式为application/json的错误信息的处理

目录 问题描述方案 问题描述 调用sse流式接口使用httpx_sse的方式 import httpxfrom httpx_sse import connect_sse# 省略无关代码try:with httpx.Client() as client:with connect_sse(client, "GET", url, paramsparam) as event_source:clear_textbox(response_t…...

在列线图上标记做为线性模型的局部解释

改造列线图做为线性模型的解释 除了使用列线图算法产生的meta数据和score数据进行线性模型的解释&#xff08;全局性解释和局部性解释&#xff09;&#xff0c;另外一种做法是改造列线图来作为线性模型的解释。这里尝试改造列线图来对线性模型进行全局性和局部性解释。 全局…...

KubeKey一键安装部署k8s集群和KubeSphere详细教程

目录 一、KubeKey简介 二、k8s集群KubeSphere安装 集群规划 硬件要求 Kubernetes支持版本 操作系统要求 SSH免密登录 配置集群时钟 所有节点安装依赖 安装docker DNS要求 存储要求 下载 KubeKey 验证KubeKey 配置集群文件 安装集群 验证命令 登录页面 一、Ku…...

CPU多级缓存与缓存一致性协议

CPU多级缓存与缓存一致性协议 CPU多级缓存和缓存一致性协议是计算机体系结构中优化性能与保证数据正确性的核心机制。以下从缓存层级设计、工作原理、一致性协议&#xff08;如MESI&#xff09;及其实现细节展开说明。 一、为什么需要多级缓存&#xff1f; CPU的计算速度远高…...

Docker用户的困境:免费项目的减少与成本的增加

摘要 在生产环境中&#xff0c;Docker用户正面临新的挑战&#xff1a;免费项目逐渐减少&#xff0c;收费服务成为主流趋势。表面上免费的选项&#xff0c;由于缺乏必要的支持和及时更新&#xff0c;反而可能导致更高的隐性成本。对于依赖Docker进行开发和部署的企业而言&#x…...

车载诊断数据库 --- AUTOSAR诊断文件DEXT简介

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...

Linux lsblk 命令详解:查看磁盘和分区信息 (中英双语)

Linux lsblk 命令详解&#xff1a;查看磁盘和分区信息 在 Linux 系统中&#xff0c;管理磁盘设备和分区是日常运维工作的重要部分。而 lsblk 命令是一个强大的工具&#xff0c;它用于列出系统中的块设备&#xff08;block devices&#xff09;信息&#xff0c;可以帮助我们快速…...

庙算兵棋推演AI开发初探(5-数据处理)

碎碎念&#xff1a;这最近几个月过得那叫一个难受&#xff0c;研究生开题没过、需求评审会在4月和6月开了2次、7月紧接着软件设计评审会&#xff0c;加班干得都是文档的事情&#xff0c;还有开会前的会务和乱七八糟的琐事&#xff0c;我们干的还被规定弄的束手束脚&#xff0c;…...

【MyBatis】#{} 与 ${} 的区别(常见面试题)

目录 前言 预编译SQL和即时SQL 什么是预编译SQL&#xff1f; 什么是即时SQL&#xff1f; 区别 #{} 与 ${}的使用 防止SQL注入 什么是SQL注入&#xff1f; 原理 排序功能 模糊查询 总结#{}和${}的区别 前言 在前面的学习中&#xff0c;我们已经知道了如果SQL语句想…...

鸿蒙开发环境搭建-入门篇

本文章讲述如何搭建鸿蒙应用开发环境&#xff1a;新建工程、虚拟机运行、真机调试等。 开发工具: DevEco Studio 5.0.3.906 os系统: mac 参考文档&#xff1a;https://juejin.cn/post/7356143704699699227 官网鸿蒙应用开发学习文档&#xff1a;https://developer.huawei.com/c…...

力扣-贪心-53 最大子数组和

思路 先把每一个值都加到当前集合中&#xff0c;记录当前的和&#xff0c;直到当前记录和小于0了&#xff0c;再重置改记录&#xff0c;再次尝试累加 代码 class Solution { public:int maxSubArray(vector<int>& nums) {int res INT32_MIN;int curSum 0;for(in…...

iOS开发 网络安全

iOS开发中的网络安全 在当前的数字化时代&#xff0c;任何应用程序都需要重视网络安全。尤其是对于iOS应用开发者而言&#xff0c;确保应用与服务器之间的数据传输安全是至关重要的。接下来&#xff0c;我们将学习“iOS开发 网络安全”的实现过程。 流程步骤 以下是实现iOS网…...