「C/C++」C/C++ 指针篇 之 指针运算
✨博客主页 | ||
---|---|---|
何曾参静谧的博客 | ||
📌文章专栏 | ||
「C/C++」C/C++程序设计 | ||
📚全部专栏 | ||
「VS」Visual Studio | 「C/C++」C/C++程序设计 | 「UG/NX」BlockUI集合 |
「Win」Windows程序设计 | 「DSA」数据结构与算法 | 「UG/NX」NX二次开发 |
「QT」QT5程序设计 | 「File」数据文件格式 | 「PK」Parasolid函数说明 |
目录
- C++ 指针运算深度解析
- 一、指针运算的基础
- 1. 指针加减整数
- 2. 指针与指针之间的运算
- 3. 指针的解引用与赋值
- 二、指针运算的应用场景
- 1. 数组遍历
- 2. 字符串处理
- 3. 动态内存管理
- 三、指针运算的潜在风险
- 1. 野指针
- 2. 内存泄漏
- 3. 数组越界
- 四、最佳实践
C++ 指针运算深度解析
在C++编程中,指针不仅是内存地址的持有者,更是连接数据与操作的桥梁。指针运算,作为C++编程的一项基本技能,其重要性不言而喻。本文将深入探讨C++中的指针运算,涵盖其基本概念、运算规则、应用场景以及潜在风险。
一、指针运算的基础
指针运算,指的是对指针变量进行的一系列算术操作,这些操作通常基于指针所指向的数据类型的大小。在C++中,指针运算主要包括指针的加减运算、指针与整数的运算以及指针之间的比较运算。
1. 指针加减整数
当对指针进行加减整数运算时,整数会被解释为指针所指向数据类型大小的倍数。例如,若指针指向int
类型(通常占4个字节),则对指针加1,实际上是将指针向前移动了4个字节。
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr; // ptr 指向数组的第一个元素
ptr++; // ptr 现在指向数组的第二个元素
ptr += 2; // ptr 现在指向数组的第四个元素(因为每次加1都跳过4个字节)
2. 指针与指针之间的运算
两个指针之间的减法运算,其结果是它们之间相隔的元素个数(基于指针所指向的数据类型)。而指针之间的比较运算,则是基于它们在内存中的相对位置。
int arr[5] = {1, 2, 3, 4, 5};
int* p1 = &arr[1]; // 指向数组的第二个元素
int* p2 = &arr[4]; // 指向数组的第五个元素
int diff = p2 - p1; // diff 的值为 3,因为 p2 和 p1 之间相隔三个 int 类型的元素
3. 指针的解引用与赋值
解引用指针(使用*
操作符)可以获取指针所指向的数据。而给指针赋值,则是将新的内存地址赋给指针变量。
int a = 10;
int* ptr = &a; // ptr 指向 a 的地址
*ptr = 20; // 通过指针修改 a 的值为 20
二、指针运算的应用场景
指针运算在C++编程中有着广泛的应用,包括但不限于数组遍历、字符串处理、动态内存管理以及数据结构实现等。
1. 数组遍历
数组名在C++中可以被视为指向数组第一个元素的指针,因此可以使用指针来遍历数组。
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr;
for (int i = 0; i < 5; ++i) {std::cout << *(ptr + i) << std::endl; // 通过指针遍历数组
}
2. 字符串处理
C++中的字符串(以字符数组的形式表示)可以通过指针进行高效处理。例如,可以使用指针来遍历字符串、查找字符或进行字符串拼接等操作。
char str[] = "Hello, World!";
char* ptr = str;
while (*ptr != '\0') {std::cout << *ptr;++ptr;
}
std::cout << std::endl;
3. 动态内存管理
在C++中,new
和delete
操作符用于动态地在堆上分配和释放内存。指针运算在这些操作中扮演着重要角色。
int* arr = new int[5]; // 在堆上分配一个包含5个整数的数组
for (int i = 0; i < 5; ++i) {*(arr + i) = i * 10; // 使用指针运算给数组赋值
}
// ... 使用数组 ...
delete[] arr; // 释放数组所占用的内存
三、指针运算的潜在风险
尽管指针运算功能强大,但它也带来了潜在的风险。若不慎使用,可能会导致程序崩溃、内存泄漏或未定义行为等问题。
1. 野指针
野指针是指未初始化或已被释放的指针。若对野指针进行解引用或运算,将导致未定义行为。
int* ptr; // 未初始化的指针(野指针)
*ptr = 10; // 未定义行为,因为 ptr 没有指向有效的内存地址
2. 内存泄漏
若在使用完动态分配的内存后未正确释放,将导致内存泄漏。长时间运行的程序可能会因此耗尽系统资源。
int* ptr = new int(10); // 动态分配内存
// ... 使用 ptr ...
// 忘记删除 ptr,导致内存泄漏
3. 数组越界
指针运算时若未正确检查边界条件,可能会导致数组越界访问。这不仅会破坏数据的完整性,还可能引发程序崩溃。
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr;
for (int i = 0; i <= 5; ++i) { // 错误的边界条件(应为 i < 5)std::cout << *(ptr + i) << std::endl; // 当 i = 5 时,将访问数组之外的内存
}
四、最佳实践
为了避免指针运算带来的风险,建议遵循以下最佳实践:
- 初始化指针:在声明指针时立即进行初始化,确保它指向有效的内存地址。
- 避免野指针:在使用指针之前检查其是否为空。若指针可能变为空(例如,在删除动态分配的内存后),请将其设置为
nullptr
。 - 正确释放内存:在使用完动态分配的内存后,务必使用
delete
或delete[]
操作符释放内存。 - 检查边界条件:在进行指针运算时,始终检查边界条件以避免数组越界访问。
- 使用智能指针:C++11引入了智能指针(如
std::unique_ptr
和std::shared_ptr
),它们能够自动管理内存并减少内存泄漏的风险。在可能的情况下,优先使用智能指针来管理动态内存。
通过遵循这些最佳实践,你可以更安全、更有效地使用C++中的指针运算。
相关文章:

「C/C++」C/C++ 指针篇 之 指针运算
✨博客主页何曾参静谧的博客📌文章专栏「C/C」C/C程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...

计算机网络网络层笔记
互联网提供的两种服务 1.虚电路服务 2.数据报服务 需要记住的是现在只用第二种也就是数据报服务 网际协议IP 物理层的中断系统:转发器(hub) 链路层的中断系统:交换机 网络层的中断系统:路由器 网络层以上:网关 如上图所示,网关是用来访问其他的网段的一个接口,网关的地…...

长亭那个检测能力超强的 WAF,出免费版啦
告诉你们一个震撼人心的消息,那个检测能力超强的 WAF——长亭雷池,他推出免费社区版啦,体验地址见文末。 八年前我刚从学校毕业,在腾讯做安全研究,看到宇森在 BlackHat 上演讲的议题 《永别了,SQL 注入》 …...
rabbitMQ RabbitTemplate 发送消息
消息发送确认机制 消息发送确认机制:消息由producer发送后,确认其是否到达broker,又是否被exchange转发至对应queue的机制 该机制分为两部分:producer---broker,exchange---queue 前者的实现依靠ConfirmCallback机制…...
本系列是《10万字208道Java经典面试题总结(附答案)》的2024修订版。
公众号 后端学习指南 本系列是《10万字208道Java经典面试题总结(附答案)》的2024修订版。 1、说说跨平台性 我们希望编写好的代码和程序,最好可以在任意平台和环境下运行,而不需要根据不同的平台,编写不同的代码。 比如,我编写的一个博客管理系统,我希望它可以在windo…...

C语言文件基础概念的理解(一)
文件基础概念 为什么有文件? 我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失 了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存…...

C++ lambda 匿名函数
看了明仕强老师的课程,C匿名函数也可以很简单 下面请看示例代码: /* lambda表达式学习,测试主函数 */#include <iostream>using namespace std;int main() {printf("Lambda test Demo:\n");//值捕获,值捕获的时候不能修…...

基于python的简单web服务器示例
安装flask flask 简介:是一个用Python编写的Web应用程序框架。 它由 Armin Ronacher 开发,他领导一个名为Pocco的国际Python爱好者团队。 Flask基于Werkzeug WSGI工具包和Jinja2模板引擎。两者都是Pocco项目 新建项目 创建好的效果 pip list 检索 安装…...

02- 模块化编程-006 ADC0808数码显示对比
1、ADC0808 芯片介绍 ADC0808是一款集成的CMOS设备,包含8位模拟至数字转换器、8通道多路复用器和与微处理器兼容的控制逻辑。8位A/D转换器采用逐次逼近作为转换技术。转换器特点包括高阻抗斩波稳定比较器、256R电压分压器、模拟开关树和逐次逼近寄存器。8通道多路复…...

又发现了Mac妙控鼠标的新使用方法
我一直是不爱用妙控鼠标的,因为用起来怪怪的,但是今天发现BettreAndBetter支持妙控鼠标的修改,于是就找出了闲置了许久的妙控鼠标试了一下 优化后的妙控鼠标使用起来就没有任何不适应的地方了,三指按下模拟中键,而且还…...

Webserver(4.6)poll和epoll
目录 pollclient.cpoll.c epollepoll.cclient.c epoll的两种工作模式水平触发边沿触发 poll poll是对select的一个改进 select的缺点在于每次都需要将fd集合从用户态拷贝到内核态,开销很大。每次调用select都需要在内核遍历传递进来的所有fd,这个开销也…...
LVGL 与 QT
LVGL 与 QT LVGL 适用于嵌入式、资源受限设备,尤其是在需要高效图形渲染和小型显示屏的场景下非常合适。它具有轻量级、模块化的特点,适用于内存和计算能力有限的硬件。 Qt 是一个功能强大的跨平台框架,适合开发桌面应用以及较为复杂的嵌入式…...

如何选择最适合的项目管理软件?2024年大厂首选7款工具盘点
选择最适合的项目管理软件对于提升团队效率、优化工作流程至关重要。2024年,各大厂在项目管理上逐渐趋向于使用更加智能化、集成化和协作性的工具。以下是如何选择最适合的项目管理软件,并对2024年大厂首选工具进行盘点。 选择适合的项目管理软件的关键…...

【数据结构】选择排序——选择排序 和 堆排序
选择排序 和 堆排序 一、选择排序选择排序的思路及其代码选择排序的弊端 二、堆排序三、速度对比同时排10000个数同时排100000个数同时拍500000个数堆排 1 亿个数 一、选择排序 选择排序的思路及其代码 选择排序思路很简单 就是经过将数组遍历选择最小值 将最小值位置的数与数…...

P11229 [CSP-J 2024] 小木棍
[CSP-J 2024] 小木棍 题目描述 小 S 喜欢收集小木棍。在收集了 n n n 根长度相等的小木棍之后,他闲来无事,便用它们拼起了数字。用小木棍拼每种数字的方法如下图所示。 现在小 S 希望拼出一个正整数,满足如下条件: 拼出这个数…...
【学习笔记】SAP ABAP——OPEN SQL(一)【SELECT语句】
SELECT语句简介 SELECT <lines> <columns> FROM <db> WHERE <condition>其中代表查询的件数,代表查询的字段名 SELECT SINGLE SELECT SINGLE <cols> FROM <db> WHERE <condition>该语句用于从数据库表中查询单条数据 …...
SQL注入(1)
1.数字型注入 例如PHP代码 “ Select username from users where id”.$_GET[id] 可以注意到,用户的输入ID字段没有任何过滤的,被直接拼接在了SQL查询语句中,由于ID没有被引号包裹ÿ…...
在AI时代,如何解决人的工作岗位被AI替代的问题?
在AI时代,工作岗位被AI替代的问题确实是一个重要的社会课题。随着技术的不断进步,许多传统的工作变得自动化,这带来了效率的提升,但也引发了就业方面的挑战。要应对这一问题,我们可以从以下几方面入手: 促进…...
Linux命令--paste
简介 paste命令用于合并文件行 参数说明 -d: 自定义间隔符,默认为tab -s:串行处理,非并行 示例 将两个文件,按照行合并 demo1.conf内容如下: name domain ip area user password roledemo2.conf内容如下 test t…...
数据结构模拟题[九]
数据结构试卷(九) 一、选择题 (30 分) 1.下列程序段的时间复杂度为( )。 for(i0 ; i<m ; i) for(j0 ; j<t ; j) c[i][j]0 ; for(i0 ; i…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...