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 引用像被限制的指针,不能直接操作地址哦~)
好啦,本篇就到这里啦,希望在前进的路上,我们都可坚持到达终点!
相关文章:
C语言速成12之指针:程序如何在内存迷宫里找宝藏?
程序员Feri一名12年的程序员,做过开发带过团队创过业,擅长Java、鸿蒙、嵌入式、人工智能等开发,专注于程序员成长的那点儿事,希望在成长的路上有你相伴!君志所向,一往无前! 0. 前言:程序如何在内存迷宫里找宝藏? 想象内存是一个巨…...

一张纸决定的高度
从我捧起《格局》这个本书开始,转眼间两个月过去了。 回头望一望,好似还在昨天。 这两个月,心态在变,前进的方向在变,但唯一不变的就是每天晚上睡前,留给自己十分钟的读书时光。 我也从来没想过…...

IP查询基础介绍
IP 查询原理 IP 地址是网络设备唯一标识,IP 查询通过解析 IP 地址获取地理位置、运营商等信息。目前主流的 IPv4(32 位)与 IPv6(128 位)协议,前者理论提供约 43 亿地址,后者地址空间近乎无限。…...

常见的gittee开源项目推荐
https://gitee.com/macrozheng/mall https://doc.ruoyi.vip/ https://eladmin.vip/ https://gitee.com/dromara/RuoYi-Cloud-Plus https://gitee.com/dromara/RuoYi-Vue-Plus https://gitee.com/ZhongBangKeJi/crmeb_java...

日常效率工具【Tools】【持续更新】
日常效率工具【Tools】 VScodevscode原理(居然和Chrome同源)Chromium(Chrome开源版)node.js:让JavaScript可以运行在wab之外的环境 配置文件setting.jesn vscode快捷键万事不求人(Ctrl K,Ctrl S)vscode修改光标所在行的背景色Gene…...
PyTorch中TensorBoardX模块与torch.utils.tensorboard模块的对比分析
文章目录 说明1. 模块起源与开发背景2. 功能特性对比3. 安装与依赖关系4. 性能与使用体验5. 迁移与兼容性策略6. 最佳实践与建议7. 未来展望8. 结论实际相关信息推荐资源 说明 TensorBoard:独立工具,只需安装tensorboard。TensorFlow:非必需…...

数据结构与算法——链式二叉树
链式二叉树 遍历方式与其规则代码的实现递归的复习前,中,后序遍历的实现二叉树结点个数二叉树叶子结点个数二叉树第k层结点个数二叉树的深度/高度二叉树查找值为x的结点二叉树销毁层序遍历 遍历方式与其规则 前序遍历:访问根结点的操作发⽣在…...

Android12 launcher3修改App图标白边问题
Android12 launcher3修改App图标白边问题 1.前言: 今天在Android12 Rom定制客制化系统应用时发现改变系统App图标的形状会出现一个问题,那就是图标被缩小了,没有显示完整,有一个白边,这在普通的App开发很少遇到&…...

【iOS】分类、扩展、关联对象
分类、扩展、关联对象 前言分类扩展扩展和分类的区别关联对象key的几种用法流程 总结 前言 最近的学习中笔者发现自己对于分类、扩展相关知识并不是很熟悉,刚好看源码类的加载过程中发现有类扩展与关联对象详解。本篇我们来探索一下这部分相关知识,首先…...

内蒙古工程系列建设工程技术人才评审条件
关于印发《内蒙古自治区工程系列建设工程专业技术人才职称评审条件》的通知 内蒙古工程系列建设工程技术人才评审条件适用范围 内蒙古工程系列建设工程技术人才评审条件之技术员评审要求 内蒙古工程系列建设工程技术人才评审条件之助理工程师评审要求 内蒙古工程系列建设工程技…...
Elasticsearch超详细安装部署教程(Windows Linux双系统)
文章目录 一、前言二、Windows系统安装部署2.1 环境准备2.2 Elasticsearch安装2.3 安装为Windows服务2.4 Head插件安装2.5 Kibana集成(可选) 三、Linux系统安装部署3.1 环境准备3.2 Elasticsearch安装3.3 系统优化3.4 启动服务3.5 安全配置(可…...
第十六章:数据治理之数据架构:数据模型和数据流转关系
本章我们说一下数据架构,说到数据架构,就很自然的想到企业架构、业务架构、软件架构,因为个人并没有对这些内容进行深入了解,所以这里不做比对是否有相似或者共通的地方,仅仅来说一下我理解的数据架构。 1、什么是架构…...

目标检测DINO-DETR(2023)详细解读
文章目录 对比去噪训练混合查询选择look forward twice 论文全称为:DETR with Improved DeNoising Anchor Boxes for End-to-End Object Detection 提出了三个新的方法: 首先,为了改进一对一的匹配效果,提出了一种对比去噪训练方法…...
基于 STM32 的蔬菜智能育苗系统硬件与软件设计
一、系统总体架构 蔬菜智能育苗系统通过单片机实时采集温湿度、光照等环境数据,根据预设阈值自动控制灌溉、补光、通风等设备,实现育苗环境的智能化管理。系统主要包括以下部分: 主控芯片:STM32F103C8T6(32 位 ARM Cortex-M3 单片机,性价比高,适合嵌入式控制)传感器模…...
实现一个带有授权码和使用时间限制的Spring Boot项目
生成和验证授权码记录授权时间和过期时间实现授权逻辑 以下是具体的实现方法: 1. 生成和验证授权码 可以使用加密技术生成和验证授权码。授权码中可以包含有效期等信息,并使用密钥进行签名。 示例代码: java复制代码 import javax.crypt…...

SGlang 推理模型优化(PD架构分离)
一、技术背景 随着大型语言模型(LLM)广泛应用于搜索、内容生成、AI助手等领域,对模型推理服务的并发能力、响应延迟和资源利用效率提出了前所未有的高要求。与模型训练相比,推理是一个持续进行、资源消耗巨大的任务,尤…...
TuyaOpen横空出世!涂鸦智能如何用开源框架重构AIoT开发范式?
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引子:AIoT开发的“不可能三角”被打破 当AI与物理世界深度融合的浪潮席卷全球,开发者们却始终面临一个“不可能三角”——开发…...

Vue语法【2】
1.插值表达式: 语法规则: {{Vue实例中data的变量名}}使用场景: 插值表达式一般使用在文本内容中,如果是元素的属性内容中则无法使用; 案例: <!DOCTYPE html> <html lang"en"> &l…...

2.2.1 05年T2
引言 本文将从一预习、二自习、三学习、四复习等四个阶段来分析2005年考研英语阅读第二篇文章。为了便于后续阅读,我将第四部分复习放在了首位。 四、复习 方法:错误思路分析总结考点文章梳理 4.1 错题分析 题目:26(细节题&…...
每日c/c++题 备战蓝桥杯(修理牛棚 Barn Repair)
修理牛棚 Barn Repair 题解 问题背景与挑战 在一个暴风雨交加的夜晚,Farmer John 的牛棚遭受了严重的破坏。屋顶被掀飞,大门也不翼而飞。幸运的是,许多牛正在度假,牛棚并未住满。然而,为了保护那些还在牛棚里的牛&am…...
6个月Python学习计划 Day 3
🎯 今日目标 掌握 while 和 for 循环的使用方式理解 range() 的工作机制实践:打印 1~100、累加、九九乘法表等常见程序逻辑 🧠 学习内容详解 while 循环 i 1 while i < 5:print(f"第 {i} 次循环")i 1📌 特点&…...

Linux虚拟文件系统(2)
2.3 目录项-dentry 目录项,即 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的关联关系。多个关联的目录项,就构成了文件系统的目录结构。和上一章中超级块和索引节点不同,目录项并不是实际存在于磁盘上的,…...

【数据结构】栈和队列(上)
目录 一、栈(先进后出、后进先出的线性表) 1、栈的概念及结构 2、栈的底层结构分析 二、代码实现 1、定义一个栈 2、栈的初始化 3、入栈 3、增容 4、出栈 5、取栈顶 6、销毁栈 一、栈(先进后出、后进先出的线性表) 1、…...

科技赋能·长效治理|无忧树建筑修缮渗漏水长效治理交流会圆满举行!
聚焦行业痛点,共话长效未来!5月16日,由无忧树主办的主题为“科技赋能长效治理”的建筑修缮渗漏水长效治理技术交流会在上海圆满举行。来自全国的建筑企业代表、专家学者、技术精英齐聚一堂,共探渗漏治理前沿技术,见证科…...

【闲聊篇】java好丰富!
1、在学习mybatis-plus的文档时,发现引入了solon依赖,才发现这是一个对标spring生态的框架,有意思! 还有若依框架,真的好丰富~~~~~~~ 2、今天面试官问我,他说很少遇到用redission做延迟队列的。后面我就反…...
STL中list的模拟
这里写目录标题 list 的节点 —— ListNodelist 的 “导览员” —— ListIteratorlist 的核心 —— list 类构造函数迭代器相关操作容量相关操作 结尾 在 C 的 STL(标准模板库)中,list 是一个十分重要的容器,它就像一个灵活的弹簧…...

6.3.2图的深度优先遍历
知识总览: 树的先根遍历: 采用递归一直找某个节点的子树直到找不到从上往下找 访问根节点1,1的子树有2、3、4,访问2,2节点子树有5访问5,5没有子树,退回到2,2还有子树6访问6,6没有子树再退回到2,2的子树都被访问了再退…...

畅游Diffusion数字人(30):情绪化数字人视频生成
畅游Diffusion数字人(0):专栏文章导航 前言:仅从音频生成此类运动极具挑战性,因为它在音频和运动之间存在一对多的相关性。运动视频的情绪是多元化的选择,之前的工作很少考虑情绪化的数字人生成。今天解读一个最新的工作FLOAT,可以生成制定情绪化的数字人视频。 目录 贡献…...

UE5 Va Res发送请求、处理请求、json使用
文章目录 介绍发送一个Get请求发送Post请求设置请求头请求体带添json发送请求完整的发送蓝图 处理收到的数据常用的json处理节点 介绍 UE5 自带的Http插件,插件内自带json解析功能 发送一个Get请求 只能写在事件图表里 发送Post请求 只能写在事件图表里 设置…...
关于flutter中Scaffold.of(context).openEndDrawer();不生效问题
原因: 在 Flutter 中,Scaffold.of(context) 会沿着当前的 context 向上查找最近的 Scaffold。如果当前的 widget 树层级中没有合适的 Scaffold(比如按钮所在的 context 是在某个子 widget 中),就找不到它。 解决办法…...