news 2026/9/6 7:54:48

深入理解指针(一):内存、地址与指针运算

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入理解指针(一):内存、地址与指针运算

1. 内存和地址

程序运行时,数据存储在内存中。内存可以看作一个连续的字节序列,每个字节都有一个唯一的编号,这个编号就是内存地址。地址从 0 开始递增,操作系统通过地址来定位和访问内存中的数据。

在 C 语言中,变量在定义时会向内存申请一块空间,这块空间的大小由变量的类型决定。例如,int类型通常占用 4 个字节,char类型占用 1 个字节。变量所占内存空间的首字节地址,就是该变量的地址。

#include <stdio.h> int main() { int a = 10; printf("变量 a 的值:%d\n", a); printf("变量 a 的地址:%p\n", &a); return 0; }

上面的代码中,&a用于取出变量a的地址,%p是打印地址的格式说明符。运行结果会显示类似0x7ffd8f3a2b4c的十六进制地址。

2. 指针变量和地址

指针变量是专门用来存放地址的变量。通过指针,我们可以间接访问和修改它所指向的变量。

定义指针变量的语法为:类型 * 变量名。例如int *p表示p是一个指向int类型数据的指针变量。

#include <stdio.h> int main() { int a = 10; int *p = &a; // p 存放变量 a 的地址 printf("a 的值:%d\n", a); printf("p 中存放的地址:%p\n", p); printf("通过 p 访问 a 的值:%d\n", *p); *p = 20; // 通过指针修改 a 的值 printf("修改后 a 的值:%d\n", a); return 0; }

这里有两个关键运算符:

  • 取地址运算符&:取出变量的地址。
  • 解引用运算符*:通过地址访问该地址上存储的数据。

当执行*p = 20时,程序会找到p中存放的地址,并往这个地址写入 20,因此变量a的值被修改为 20。

3. 指针变量类型的意义

指针变量本身存放的是地址,无论指向什么类型,指针变量所占的内存大小通常是相同的(在 64 位系统上为 8 字节)。那么为什么指针还要区分类型呢?

指针的类型决定了两个重要信息:

  • 解引用时访问的字节数int *解引用时读取 4 个字节,char *解引用时只读取 1 个字节。
  • 指针加减运算时的步长int *加 1 跳过 4 个字节,char *加 1 只跳过 1 个字节。
#include <stdio.h> int main() { int a = 0x12345678; int *p = &a; char *c = (char *)&a; printf("int 指针解引用:%x\n", *p); printf("char 指针解引用:%x\n", *c); printf("int 指针加 1 的地址:%p\n", p + 1); printf("char 指针加 1 的地址:%p\n", c + 1); return 0; }

运行结果中,p + 1p大 4 个字节,而c + 1c大 1 个字节。这说明指针类型决定了指针运算的步长,也决定了解引用时能访问的数据范围。

4. 指针运算

指针运算主要包括以下几种:

  • 指针加整数p + n表示向后移动n个同类型元素。
  • 指针减整数p - n表示向前移动n个同类型元素。
  • 指针减指针p1 - p2表示两个指针之间相隔的元素个数。
  • 指针比较:可以用关系运算符比较两个指针指向的地址大小。

指针运算在遍历数组时非常常用。下面通过一个数组遍历的例子来演示:

#include <stdio.h> int main() { int arr[] = {10, 20, 30, 40, 50}; int *p = arr; // 数组名就是首元素地址 for (int i = 0; i < 5; i++) { printf("arr[%d] = %d,地址:%p\n", i, *(p + i), p + i); } // 指针减指针:计算元素个数 int *start = &arr[0]; int *end = &arr[4]; printf("相隔元素个数:%ld\n", end - start); return 0; }

在这个例子中,*(p + i)等价于arr[i]p + i指向数组第i个元素。而end - start的结果是 4,表示两个指针之间相隔 4 个元素。

需要注意的是,指针运算必须限定在同一个数组或同一块连续内存范围内,否则结果是未定义的,容易引发难以排查的错误。

5. 小结

本文介绍了指针的基础知识:内存地址是数据在内存中的唯一编号,指针变量用于存放地址,指针类型决定了解引用范围和运算步长,指针运算则提供了灵活访问连续内存的手段。理解这些概念,是后续学习数组、字符串、函数指针和动态内存管理的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 7:54:19

STM32离线语音控制智能家居实战:从原理图到Proteus仿真与实物调试

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

作者头像 李华
网站建设 2026/9/6 7:51:46

AI率检测工具免费版能测什么?报告定位和字数限制怎么比较?

AI率检测工具免费版能测什么&#xff1f;报告定位和字数限制怎么比较&#xff1f; 论文初稿刚写完&#xff0c;多数人的第一个动作不是改&#xff0c;而是先找个免费的AI率检测工具摸个底。摸完底之后卡住的人也最多&#xff1a;免费版丢回来一个总分&#xff0c;比如AIGC疑似…

作者头像 李华
网站建设 2026/9/6 7:49:58

九紫离火运全面解读:顺势而为的时代机遇与风水布局指南

当历史的指针划过2024年&#xff0c;我们正式步入三元九运中的“九紫离火运”。这是一个属于文明、智慧、美学与心灵革新的时代。无论你是否关注传统国学&#xff0c;你身边悄然变化的产业格局、审美取向、生活方式&#xff0c;都在印证着火运的启动。看懂九紫离火&#xff0c;…

作者头像 李华
网站建设 2026/9/6 7:47:30

Java开发者转型AI Agent岗位:技能迁移与实战指南

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

作者头像 李华
网站建设 2026/9/6 7:45:57

一次 SPI 插件加载崩溃:ServiceLoader 的懒迭代藏着 3 个坑

去年双十一前一周&#xff0c;我们的网关在一次灰度发布后直接启动失败&#xff0c;报错 java.util.ServiceConfigurationError: xxx.Codec: Provider com.xxx.RedisCodec could not be instantiated。定位到根因那一刻&#xff0c;我对 SPI&#xff08;Service Provider Inter…

作者头像 李华
网站建设 2026/9/6 7:45:02

基于 Flask 的企业级 CMS 架构设计与实现

从单页展示到插件化、RBAC、工作流、全文搜索、对象存储——一套轻量级 CMS 的完整技术演进与架构拆解。 一、引言&#xff1a;企业建站的技术选型困境 为企业搭建官网时&#xff0c;技术团队常面临这样的选择困境&#xff1a; WordPress&#xff1a;生态庞大但 PHP 技术栈在…

作者头像 李华