指针 + 1 到底加了多少?——指针运算的本质,Day12 学习记录

发布时间:2026/9/15 9:43:10

指针 + 1 到底加了多少?——指针运算的本质,Day12 学习记录 1. 指针运算的本质p1 不是地址加 1学指针的时候我一直以为p1就是地址值直接加 1。直到有一天写代码发现int *p和char *p做p1的结果完全不一样——同一个操作打印出来的地址偏移居然差了 4 倍。于是我明白了一件事指针加 1加的不是 1 个字节而是 1 个元素的大小。提出问题既然指针本身存的是一个地址值那p1到底加了多少为什么int*和char*的表现不同示例#includestdio.hintmain(){inta10;charcA;int*p_inta;char*p_charc;printf(p_int %p\n,p_int);printf(p_int 1 %p\n,p_int1);printf(p_char %p\n,p_char);printf(p_char 1 %p\n,p_char1);return0;}在我的机器上输出类似这样具体值每次运行不同但偏移规律固定p_int 0x7ffe1a3b5c2c p_int 1 0x7ffe1a3b5c30 ← 差 4 字节 p_char 0x7ffe1a3b5c2b p_char 1 0x7ffe1a3b5c2c ← 差 1 字节为什么这样p N的实际偏移字节数等于N × sizeof(基类型)。编译器在编译时就知道指针指向的类型占多大空间所以自动帮你算好偏移量。int在我的机器上占 4 个字节所以p_int 1地址向后跳 4。char占 1 个字节所以p_char 1地址向后跳 1。这个设计的好处是你不用自己算偏移字节数编译器帮你保证p1刚好指向「下一个元素」的起始位置。指针相减也是类似逻辑两个同类型指针相减结果是它们之间相差的元素个数不是字节数。比如(p 5) - p的结果是 5。一句总结指针运算的本质是元素级别的地址偏移步长取决于指针指向的类型大小不是机械的地址值加 1。2. 指针操作一维数组三种写法背后是同一条路学过指针运算的本质之后再回头看数组很多曾经模糊的地方突然通了。提出问题明明数组和指针是两个东西为什么a[i]和*(p i)能访问到同一个元素它们底层到底有什么关系示例#includestdio.hintmain(){intarr[]{10,20,30,40,50};int*parr;// arr 就是首元素地址 arr[0]// 三种等价写法for(inti0;i5;i){printf(%d ,arr[i]);// 下标法printf(%d ,*(pi));// 指针偏移法printf(%d ,p[i]);// 指针也可以像数组一样用下标}return0;}三种写法输出的结果完全相同10 20 30 40 50。为什么这样数组名arr在表达式中会被隐式转换成指向首元素的指针所以arr和p存的是同一个地址。编译器处理arr[i]时内部就是按*(arr i)来计算的——下标法只是指针偏移的语法糖。反过来指针p也能用p[i]这种写法因为p[i]同样等价于*(p i)。指针遍历数组的几种实际写法// 写法一下标法最直观for(inti0;i5;i){printf(%d ,arr[i]);}// 写法二指针偏移法逐步后移int*parr;for(inti0;i5;i){printf(%d ,*(pi));}// 写法三指针自增法最贴近“遍历”语义int*parr;for(inti0;i5;i){printf(%d ,*p);p;// 每次后移一个 int 元素}第三种写法最常见于实际项目每轮循环打印当前元素然后p让指针指向下一个元素直到遍历完整个数组。一句总结数组名就是首元素地址arr[i]和*(pi)和p[i]底层完全一致选择哪种写法只是习惯问题。3. 指针操作字符串字符指针遍历与 char* 和 char[] 的区别字符串本质上是一个以\0结尾的字符数组用指针操作字符串是 C 语言里非常高频的用法。提出问题给一个字符串怎么用指针遍历打印每个字符char *p和char s[]看起来都能存字符串它们到底有什么区别示例#includestdio.hintmain(){chars[]hello;char*ps;// p 指向 s 的首字符 hwhile(*p!\0){printf(%c,*p);p;// 指针后移一个 char即 1 个字节}printf(\n);return0;}输出hello。每次循环打印当前字符然后p让指针指向下一个字符直到遇见\0终止。为什么这样C 语言字符串以\0ASCII 码 0结尾所以while (*p ! \0)可以自然控制循环结束。p每次偏移sizeof(char) 1字节刚好指向下一个字符。char *p与char s[]的关键区别char *p hello;char s[] hello;本质指针指向字符串常量区数组在栈上开辟空间并拷贝内容可否修改内容❌ 不可改常量区只读修改会崩溃✅ 可改如s[0] H;指针本身可重新指向别的字符串数组名不可重新赋值踩坑实录我曾经写过char *p hello; p[0] H;想改成大写结果程序直接崩溃。原因就是p指向的是字符串常量区那片内存只读不可写。如果你需要可修改的字符串请用char s[] hello;。一句总结字符指针遍历字符串用*p ! \0判断结束char*指向常量区不可修改char[]在栈上可自由修改。4. const 修饰指针离谁近就限定谁const 修饰指针是初学者最容易混淆的点之一四种写法只差一个 const 的位置含义就完全不同。提出问题const char *s、char const *s、char *const s、const char *const s到底怎么区分有没有简单的记忆方法示例与对比写法含义通俗理解const char *s指向的内容不可修改不能通过*s改字符但s可以指向别处char const *s同上const 在*左边就行——const char *s是更常见的写法char const *s也合法但不常用和上一条完全等价char *const s指针本身不可修改s不能指向别处但可以通过*s改内容const char *const s两者都不可修改既不能改指向也不能改内容为什么这样记忆原则只有一句话const 离谁近就限定谁。const挨着char限定的是*s内容不可改。const挨着*s即*const s限定的是s本身指针不可改。实际应用建议函数形参如果只读不写一律用const char *。比如int puts(const char *s);调用者传字符串常量、数组名、const char*变量都能接住函数内部还不会误修改字符串代码更严谨。一句总结const 修饰指针看相对位置挨着类型限定内容挨着指针变量限定指向。5. 今日练习题解用指针思维实战两道题到做练习的时候我才发现光听懂原理不够真正写代码才能暴露理解漏洞。1单词倒置——「how are you」→「you are how」我当时的第一反应拆分单词存数组、反向拼接。但老师说有更简洁的两遍逆序法。正确思路先把整个字符串逆序how are you→uoy era woh再把每个单词单独逆序uoy→youera→arewoh→how整个过程用指针控制区间边界逆序函数只交换首尾字符。注意第一步逆序整个字符串时空格也被当作普通字符参与逆序会从中间被移到两端。不过没关系——后续对每个单词单独逆序时空格会自然归位完整代码#includestdio.h#includestring.h// reverse: 将字符串区间 [start, end) 内的字符逆序// 注意end 指向最后一个字符的下一位置即空格或\0不包含在交换中voidreverse(char*start,char*end){--end;// 让 end 指向最后一个有效字符while(startend){chartmp*start;// 交换首尾字符*start*end;*endtmp;start;end--;}}intmain(){charstr[]how are you;printf(原字符串: %s\n,str);intlenstrlen(str);// 第一步整个字符串逆序不包含 \0reverse(str,strlen);printf(整体逆序: %s\n,str);// 第二步逐个单词逆序char*pstr;while(*p!\0){// 跳过空格while(*p )p;if(*p\0)break;// 已到字符串末尾char*word_startp;// 单词起始位置// 找到单词结束下一个空格或字符串结尾while(*p! *p!\0)p;char*word_endp;// 单词结束位置指向空格或\0// 逆序当前单词reverse(word_start,word_end);}printf(单词逆序后: %s\n,str);return0;}编译运行结果原字符串: how are you 整体逆序: uoy era woh 单词逆序后: you are how最终结果正确。2间隔输出——「Computer Science」→「Cmue cec」思路从首字符开始每次跳过 1 个字符步长 2相当于只取偶数下标的字符。用指针实现就是p初始指向首字符每次p 2完整代码#includestdio.hintmain(){charstr[]Computer Science;char*pstr;printf(原字符串: %s\n,str);printf(间隔输出: );while(*p!\0){putchar(*p);// 打印当前字符p2;// 步长 2跳过下一个字符}printf(\n);return0;}编译运行结果原字符串: Computer Science 间隔输出: Cmue cec直到超出字符串末尾。一句总结指针解决字符串问题的关键是「用指针控制区间」而不是「用下标数位置」代码会更紧凑也更贴近内存思维。今日避坑指南坑现象正确理解p1 以为是地址加 1打印地址发现偏移数值不对偏移量 1 × sizeof(基类型)char *p abc; p[0]A;程序崩溃字面串在常量区不可写用char s[]用比较两个字符串永远不成立或结果不对比的是地址应使用strcmp()const 位置一头雾水四种写法混淆const 离谁近限定谁数组名和指针划等号以为sizeof(s)能拿到字符串长度数组名在多数表达式中会退化为指针但在sizeof和运算中不会退化因此sizeof(数组名)返回整个数组的字节数今日学习感悟今天才真正搞明白指针运算不是在玩地址数字游戏而是编译器在默默帮我按元素大小算偏移。以前记不住const的那几种写法现在用「离谁近就限定谁」这条口诀基本不会搞混了。写单词倒置的时候第一次没考虑\0逆序完打印多了一堆乱码找半天才发现是字符串结束符也被反转了——如果 reverse 函数把\0也纳入交换范围\0就会被移到开头导致字符串被截断。实际实现时reverse 的区间应排除\0只处理有效字符部分。这种低级错误真得亲自动手写过才会长记性。Day12 最大的收获指针不是玄学它是一套有规律可循的内存操作逻辑理解 sizeof 和元素粒度的概念就通了八成。
延伸阅读

更多相关文章

2026/9/13 8:59:09

如何在5分钟内集成GitHub Tag Action?超简单入门教程

如何在5分钟内集成GitHub Tag Action?超简单入门教程 【免费下载链接】github-tag-action A Github Action to automatically bump and tag master, on merge, with the latest SemVer formatted version. Works on any platform. 项目地址: https://gitcode.com/…

2026/9/15 0:54:36

基于感知哈希的图片查重系统设计与优化

1. 项目概述:基于感知哈希的图片查重系统这个项目实现了一个能够快速识别重复或相似图片的系统,核心采用感知哈希(pHash)算法计算图片指纹,配合汉明距离进行相似度比对。我在实际开发中发现,这套方案特别适…

2026/9/7 16:11:54

Athena高级教程:自定义论文结构与公式生成的实用指南

Athena高级教程:自定义论文结构与公式生成的实用指南 【免费下载链接】Athena Structure your STEM essay in several minutes with Generative AI. 项目地址: https://gitcode.com/gh_mirrors/athena13/Athena Athena是一款基于生成式AI的STEM论文辅助工具&…

2026/9/15 9:42:03

5年AI岗年薪差50万?大厂与创业公司薪酬结构深度拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 9:42:03

STM32嵌入式开发中C++11的工程化落地实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/15 9:42:03

网站被黑挂马?3个实战案例拆解seo关键词排名优化品牌费用

网站被黑挂马?3个实战案例拆解seo关键词排名优化品牌费用 上个月接到一个杭州做外贸的老板电话,声音都在抖。他说网站首页突然变成赌博广告,后台被植入后门,客户投诉电话被打爆。更惨的是,他花两万块做的seo关键词排名优化品牌,因为网站被降权,…

2026/9/15 9:37:02

Spring Modulith:模块化单体架构的Java实践

1. 项目概述:从"大泥球"到模块化单体的演进之路在Java企业级开发领域,"大泥球"(Big Ball of Mud)这个术语形象地描述了许多项目最终陷入的困境——随着业务增长,代码逐渐变成一团相互纠缠、边界模…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码