C语言速成12之指针:程序如何在内存迷宫里找宝藏?

程序员Feri一名12年+的程序员,做过开发带过团队创过业,擅长Java、鸿蒙、嵌入式、人工智能等开发,专注于程序员成长的那点儿事,希望在成长的路上有你相伴!君志所向,一往无前!


0. 前言:程序如何在内存迷宫里找宝藏?

想象内存是一个巨大的图书馆,每个书架格子(1 字节)都贴着独一无二的门牌号(地址)。

当我们写下 int num = 5;,就像在图书馆里租了 4 个相邻的格子,把数字 5 藏了进去。

现在问题来了:程序怎么找到这 4 个格子里的宝藏?

有两种寻宝方式:

直接寻宝:喊出格子的昵称(变量名 num),编译器会帮你翻译成具体门牌号

间接寻宝:先找到记录门牌号的小本本(指针),通过本本上的地址找到宝藏,这就是 C 语言的 "指针魔法"

接下来,我们将揭开这本神奇小本本的秘密,让你成为内存迷宫的寻宝大师!

1. 指针:给内存地址取个 "外号"

1.1 内存格子的门牌号系统

内存就像一栋无限延伸的公寓楼,每个房间(1 字节)都有门牌号(如 0x0001)。当我们定义int num = 5时:

num是 4 间相连公寓的 "小区名字"

数字 5 是存在这 4 间公寓里的宝藏

第一间公寓的门牌号(如 0x0001)就是num的 "指针",相当于给地址取了个好记的外号

1.2 指针家族成员大阅兵

角色名称

真实身份

生活类比

变量

带名字的储物箱

标着 "零食" 的抽屉,里面装着薯片

变量名

储物箱的标签

抽屉上的 "零食" 标签

变量值

储物箱里的东西

抽屉里的薯片

指针

储物箱的门牌号

抽屉在柜子里的位置编号(如 3 层 5 号)

指针变量

专门记门牌号的小本本

记录所有抽屉位置的笔记本,翻开某页写着 "零食抽屉:3 层 5 号"

魔法口诀:指针不是具体的门牌号,而是带 "户型" 的地址 ——int指针知道自己要找的是 4 间相连的公寓(4 字节),char只找 1 间单身公寓(1 字节)

2. 指针变量:会记地址的 "智能笔记本"

2.1 召唤指针变量的咒语

数据类型 *指针变量名 = 初始地址; // 咒语格式

int *p = # // 召唤一个叫p的笔记本,专门记int型变量的地址

数据类型:规定笔记本只能记某种户型的地址,比如int*只能记 4 字节公寓的地址

*符号:这是指针变量的身份标识,就像笔记本封面上写着 "地址专用"

危险警告:没初始化的指针就像空白笔记本,随便用可能记着错误地址,导致程序去危险区域搞破坏!

2.2 内存里的 "地址传递游戏"

当执行int num = 5; int *ptr = #时:

num住在 0x1000-0x1003 公寓,存着数字 5

ptr住在 0x2000-0x2003 公寓,里面写着 "0x1000"(num 的门牌号)

通过*ptr就能打开 num 的公寓,就像对着笔记本念咒

语:"根据地址 0x1000,取出里面的宝藏!"

3. 指针的神奇应用:让程序玩出花样

3.1 变量操作:隔空改值的魔法

// 定义一个交换魔法函数void swap(int *x, int *y) {int temp = *x; // 从x地址的公寓取出宝藏存到临时盒子*x = *y;       // 把y地址的宝藏放进x的公寓*y = temp;     // 把临时盒子的宝藏放回y的公寓
}int main() {int a=1, b=2;swap(&a, &b); // 告诉swap函数:a住在&a,b住在&bprintf("a=%d b=%d", a, b); // 见证奇迹:a和b的值交换了!
}

魔法原理:直接告诉函数变量的真实地址,让函数能直接修改原始数据,不用带复印件(值传递),省内存又高效!

3.2 数组遍历:在内存街道上大步流星

int arr[] = {1,2,3,4,5};
int *p = arr; // p指向数组第一个元素的地址,就像站在街道起点for(int i=0; i<5; i++) {printf("%d ", *(p+i)); // p+i表示向前走i步,每步跨4米(int占4字节)
}

速度秘诀:指针直接按地址蹦跶,比数组下标(还要计算偏移量)快得多,就像开着跑车在内存街道飞驰!

3.3 动态数据结构:搭积木般建链表

// 定义链表节点:每个节点是一块带地址的积木
typedef struct Node {int data;          // 积木上的数字struct Node *next; // 积木上的箭头,指向下一块积木
} Node;// 创建积木的工厂函数
Node* createNode(int value) {Node* newNode = (Node*)malloc(sizeof(Node)); // 申请一块新积木newNode->data = value;                        // 在积木上写数字newNode->next = NULL;                          // 箭头先指向空return newNode;                                // 交出这块积木
}// 搭建链表:把积木用箭头连起来
Node* head = createNode(1);
head->next = createNode(2); // 第一块积木的箭头指向第二块

数据结构奥秘:指针就像积木的箭头,让零散的内存块能连成任意形状,链表、树、图全靠这些箭头!

4. 指针运算:在内存地址上玩数学游戏

4.1 取址咒 &:打听变量住哪儿

int num = 10;printf("num住在:%p\n", (void*)&num); // 输出类似0x7fff5fbff7d4的门牌号

注意:数组名天生会变魔术!int arr[5]; int *p=arr;等价于p=&arr[0],直接指向第一个元素的地址。

4.2 解引用咒 *:按地址拆快递

int a=2024, *p=&a;
printf("a的快递是:%d\n", *p); // 输出2024,就像按快递单地址拆开包裹
*p = 2025; // 直接修改地址里的内容,相当于往包裹里塞新东西

双重解引用:如果 p 是记地址的笔记本,

**pp 就是记笔记本位置的书包!
int **pp = &p;
**pp就是从书包里拿出笔记本,再看里面的地址。

4.3 指针加减法:在内存街道上散步

向前走 n 步:指针 + n 表示往后走 n 个 "户型长度",比如int指针走 1 步是 4 字节,char走 1 步是 1 字节

int arr[] = {1,2,3};
int *p = arr;
printf("%d", *(p+2)); // 从起点走2步(8字节),拿到第三个元素3

计算距离:两个指针相减得到中间的元素个数(需在同一块内存区域)

int len = &arr[2] - &arr[0]; // 结果是2,表示中间有2个元素(索引0和1)

4.4 危险警告:别碰这些指针地雷!

野指针:没初始化或指向已释放内存的指针,就像没有目的地的导航,可能带你冲进悬崖(程序崩溃)

int *p; // 没初始化的p,里面可能存着随机地址
*p = 10; // 危险!往未知地址写数据,可能破坏重要内存

类型乱转:强制把double转成int,就像把大箱子塞进小抽屉,数据会被挤变形!

double d=3.14;
int *p = (int*)&d; // 强行用int指针读double地址,得到的是乱码值

5. 指针安全手册:避免翻车的 3 个铁律

5.1 上车先系安全带:初始化指针

int *p = NULL; // 空指针,就像笔记本第一页写着"无地址"
int a, *q = &a; // 直接指向有效变量a的地址,安全起步

开车前检查: if(p != NULL)再操作,避免空指针 dereference 车祸。

5.2 车型要匹配:指针类型别乱改

double d=3.14;
// 错误示范:让小卡车(int*)去拉巨型货物(double变量)
int *p = (int*)&d; 
// 正确做法:用对应的货车(double*)
double *pd = &d;

5.3 借的内存要还:动态内存管理

int *p = malloc(sizeof(int)); // 向系统借了一块内存
free(p); // 用完要还!
p = NULL; // 还完标记为NULL,防止再次误用

内存泄漏警告:借了不还,系统内存会越来越少,程序最终会 "内存不足" 卡死!

结语:掌握指针,成为内存世界的造物主

指针就像 C 语言给程序员的 "内存造物主权限":

你可以直接操控内存地址,实现底层魔法

用指针变量记录地址,像管理地图一样管理内存

通过指针运算,在内存迷宫里精准移动

从简单的变量交换,到复杂的操作系统内核,指针贯穿 C 语言的每个角落。建议打开编译器,亲手写几个指针程序:试试用指针交换变量,用指针遍历数组,甚至搭一个简单的链表 —— 在实践中感受指针的魔力!

每日灵魂拷问:如果 C 语言没有指针,程序员该怎么实现动态数据结构?Java 的 "引用" 和 C 的指针有啥区别?(提示:Java 引用像被限制的指针,不能直接操作地址哦~)

好啦,本篇就到这里啦,希望在前进的路上,我们都可坚持到达终点!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

部署n8n

https://github.com/n8n-io/n8n docker volume create n8n_data docker run -it --rm --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n Discover 2192 Automation Workflows from the n8ns Community

ABP VNext + Orleans:Actor 模型下的分布式状态管理最佳实践

ABP VNext Orleans&#xff1a;Actor 模型下的分布式状态管理最佳实践 &#x1f680; &#x1f4da; 目录 ABP VNext Orleans&#xff1a;Actor 模型下的分布式状态管理最佳实践 &#x1f680;一、引言&#xff1a;分布式系统的状态挑战 &#x1f4a1;二、架构图与技术栈 &am…

构建安全AI风险识别大模型:CoT、训练集与Agent vs. Fine-Tuning对比

构建安全AI风险识别大模型:CoT、训练集与Agent vs. Fine-Tuning对比 安全AI风险识别大模型旨在通过自然语言处理(NLP)技术,检测和分析潜在的安全威胁,如数据泄露、合规违规或恶意行为。本文从Chain-of-Thought (CoT)设计、训练集构建、以及Agent-based方法与**AI直接调优…

Baklib内容中台的主要构成是什么?

Baklib内容中台核心架构 Baklib作为一站式知识管理平台的核心载体&#xff0c;其架构设计围绕智能搜索引擎优化技术与多终端适配响应系统展开。通过模块化内容组件的灵活配置&#xff0c;企业可快速搭建知识库、FAQ页面及帮助中心等标准化场景&#xff0c;同时借助可视化数据看…

Ubuntu Desktop 24.04 常用软件安装步骤

文章目录 Ubuntu Desktop 24.04 常用软件安装步骤Snipaste F1快捷截图&#xff08;超方便 | 我6台电脑每台都用&#xff09;搜狗输入法快速浏览工具 | 空格键快速预览文件壁纸工具 | varietySSH 工具 | Termius 终端分屏工具 | TmuxCaffeine | 避免息屏小工具 一些设置将启动台…

详细使用@rollup/plugin-inject的方式

rollup/plugin-inject 是一个 Rollup 插件&#xff0c;它允许你在构建时自动注入模块中的变量引用&#xff0c;避免手动在每个文件中 import。Vite 使用的是 Rollup 构建底层&#xff0c;因此该插件在 Vite 项目中也适用。 一、使用场景 比如你希望在代码中不手动写 import { …

Day 0017:Web漏洞扫描(OpenVAS)解析

一、NVT脚本解析&#xff1a;漏洞检测的“DNA” 1. NVT脚本结构 每个NVT脚本都是一个Lua脚本&#xff0c;包含以下核心模块&#xff1a; lua -- 示例&#xff1a;检测Apache HTTPd 2.4.49路径穿越漏洞&#xff08;CVE-2021-41773&#xff09; script_id "1.3.6.1.4.1.…

【HarmonyOS Next之旅】DevEco Studio使用指南(二十六) -> 创建端云一体化开发工程

目录 1 -> 创建HarmonyOS应用工程 1.1 -> 新建工程 1.1.1 -> 前提条件 1.1.2 -> 选择模板 1.1.3 -> 配置工程信息 1.1.4 -> 关联云开发资源 1.2 -> 工程初始化配置 1.2.1 -> 自动开通云开发服务 1.3 -> 端云一体化开发工程目录结构 1.3.1…

Python 包管理工具 uv

Python 包管理工具 uv 是由 Astral 团队&#xff08;知名工具 Ruff 的开发者&#xff09;基于 Rust 开发的新一代工具&#xff0c;旨在通过高性能和一体化设计革新 Python 生态的依赖管理体验。以下是其核心特性、优势及使用指南的全面解析&#xff1a; 一、uv 的核心优势 极致…

何谓第二大脑?读书笔记

2025/05/11 发表想法 每个人都是矛盾结合体&#xff0c;既想学到新知识、新的能力&#xff0c;又想没办法专注的学习&#xff0c;既无法专注有渴望学习新技能&#xff0c;逐渐会产生焦虑、失眠等负面症状&#xff0c;这就是现实社会现照&#xff0c;那怎么办&#xff1f;我们能…

动态防御体系实战:AI如何重构DDoS攻防逻辑

1. 传统高防IP的静态瓶颈 传统高防IP依赖预定义规则库&#xff0c;面对SYN Flood、CC攻击等常见威胁时&#xff0c;常因规则更新滞后导致误封合法流量。例如&#xff0c;某电商平台遭遇HTTP慢速攻击时&#xff0c;静态阈值过滤无法区分正常用户与攻击者&#xff0c;导致订单接…

为什么在设置 model.eval() 之后,pytorch模型的性能会很差?为什么 dropout 影响性能?| 深度学习

在深度学习的世界里&#xff0c;有一个看似简单却让无数开发者困惑的现象&#xff1a; “为什么在训练时模型表现良好&#xff0c;但设置 model.eval() 后&#xff0c;模型的性能却显著下降&#xff1f;” 这是一个让人抓耳挠腮的问题&#xff0c;几乎每一个使用 PyTorch 的研究…

[爬虫知识] http协议

相关爬虫专栏&#xff1a;JS逆向爬虫实战 爬虫知识点合集 爬虫实战案例 引言&#xff1a;爬虫与HTTP的不解之缘 爬虫作用&#xff1a;模拟浏览器请求网页为何要懂HTTP&#xff1a;http是网络通信的基石&#xff0c;爬虫抓取数据就是通过HTTP协议进行的&#xff0c;了解http有…

《Spark/Flink/Doris离线实时数仓开发》目录

欢迎加入《Spark/Flink/Doris离线&实时数仓开发》付费专栏&#xff01;本专栏专为大数据工程师、数据分析师及准备大数据面试的求职者量身打造&#xff0c;聚焦Spark、Flink、Doris等核心技术&#xff0c;覆盖离线与实时数仓开发的全流程。无论你是想快速上手项目、提升技术…

事务基础概念

事务 事务是什么&#xff1f; 事务是一种机制&#xff0c;一个操作序列&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有命令作为一个整体一起向系统提交或者撤销操作请求&#xff0c;即统一这组命令要么一起执行&#xff0c;要么一起不执行 简短概况就是&#…

四、【API 开发篇 (上)】:使用 Django REST Framework 构建项目与模块 CRUD API

【API 开发篇 】&#xff1a;使用 Django REST Framework 构建项目与模块 CRUD API 前言为什么选择 Django REST Framework (DRF)&#xff1f;第一步&#xff1a;创建 Serializers (序列化器)第二步&#xff1a;创建 ViewSets (视图集)第三步&#xff1a;配置 URLs (路由)第四步…

【北京盈达科技】GEO优化中的多模态了解

多模态数据处理领域&#xff0c;“模态”指的是不同类型的数据形式&#xff0c;每种模态都具有独特的结构和信息表达方式。以下是12种可能的模态类型&#xff0c;这些模态在实际应用中可以根据具体场景进行组合和处理&#xff1a; 1. 文本模态 描述&#xff1a;以文字形式存在…

推进可解释人工智能迈向类人智能讨论总结分享

目录 一、探索“可解释人工智能”&#xff1a;AI如何从“黑箱”走向“透明大师” 二、走进可解释人工智能&#xff1a;让AI的决策变得透明 &#xff08;一&#xff09;几种常见的特征导向方法 &#xff08;二&#xff09;像素级方法 1. 层次相关传播&#xff08;LRP&#…

【Qt】Qt 5.9.7使用MSVC2015 64Bit编译器

环境 Qt版本&#xff1a;5.9.7 VS版本&#xff1a;VS2022 步骤 1、安装VS2022 三个必选项&#xff1a; a、使用C的桌面开发 b、Windows10 SDK 版本&#xff1a;10.0.18362.0 c、MSVC v140 VS 2015 生成工具 Windows10 SDK安装完成后&#xff0c;需要增加安装调试器。 2…

超越OpenAI CodeX的软件工程智能体:Jules

目前AI编码代理&#xff08;coding agent&#xff09;领域正迅速崛起&#xff0c;Google推出了一款名为Jules的非同步编码代理&#xff08;asynchronous coding agent&#xff09;&#xff0c;主要针对专业开发者&#xff0c;与传统在开发环境中直接辅助编码的Cursor或Windsurf…