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

news2025/5/26 4:14:59

程序员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住在&b
    printf("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.coloradmin.cn/o/2385824.html

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

相关文章

一张纸决定的高度

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

IP查询基础介绍

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

常见的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原理&#xff08;居然和Chrome同源&#xff09;Chromium(Chrome开源版)node.js:让JavaScript可以运行在wab之外的环境 配置文件setting.jesn vscode快捷键万事不求人&#xff08;Ctrl K,Ctrl S&#xff09;vscode修改光标所在行的背景色Gene…

数据结构与算法——链式二叉树

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

Android12 launcher3修改App图标白边问题

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

【iOS】分类、扩展、关联对象

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

内蒙古工程系列建设工程技术人才评审条件

关于印发《内蒙古自治区工程系列建设工程专业技术人才职称评审条件》的通知 内蒙古工程系列建设工程技术人才评审条件适用范围 内蒙古工程系列建设工程技术人才评审条件之技术员评审要求 内蒙古工程系列建设工程技术人才评审条件之助理工程师评审要求 内蒙古工程系列建设工程技…

目标检测DINO-DETR(2023)详细解读

文章目录 对比去噪训练混合查询选择look forward twice 论文全称为&#xff1a;DETR with Improved DeNoising Anchor Boxes for End-to-End Object Detection 提出了三个新的方法&#xff1a; 首先&#xff0c;为了改进一对一的匹配效果&#xff0c;提出了一种对比去噪训练方法…

SGlang 推理模型优化(PD架构分离)

一、技术背景 随着大型语言模型&#xff08;LLM&#xff09;广泛应用于搜索、内容生成、AI助手等领域&#xff0c;对模型推理服务的并发能力、响应延迟和资源利用效率提出了前所未有的高要求。与模型训练相比&#xff0c;推理是一个持续进行、资源消耗巨大的任务&#xff0c;尤…

Vue语法【2】

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

2.2.1 05年T2

引言 本文将从一预习、二自习、三学习、四复习等四个阶段来分析2005年考研英语阅读第二篇文章。为了便于后续阅读&#xff0c;我将第四部分复习放在了首位。 四、复习 方法&#xff1a;错误思路分析总结考点文章梳理 4.1 错题分析 题目&#xff1a;26&#xff08;细节题&…

Linux虚拟文件系统(2)

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

【数据结构】栈和队列(上)

目录 一、栈&#xff08;先进后出、后进先出的线性表&#xff09; 1、栈的概念及结构 2、栈的底层结构分析 二、代码实现 1、定义一个栈 2、栈的初始化 3、入栈 3、增容 4、出栈 5、取栈顶 6、销毁栈 一、栈&#xff08;先进后出、后进先出的线性表&#xff09; 1、…

科技赋能·长效治理|无忧树建筑修缮渗漏水长效治理交流会圆满举行!

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

【闲聊篇】java好丰富!

1、在学习mybatis-plus的文档时&#xff0c;发现引入了solon依赖&#xff0c;才发现这是一个对标spring生态的框架&#xff0c;有意思&#xff01; 还有若依框架&#xff0c;真的好丰富~~~~~~~ 2、今天面试官问我&#xff0c;他说很少遇到用redission做延迟队列的。后面我就反…

6.3.2图的深度优先遍历

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

畅游Diffusion数字人(30):情绪化数字人视频生成

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

UE5 Va Res发送请求、处理请求、json使用

文章目录 介绍发送一个Get请求发送Post请求设置请求头请求体带添json发送请求完整的发送蓝图 处理收到的数据常用的json处理节点 介绍 UE5 自带的Http插件&#xff0c;插件内自带json解析功能 发送一个Get请求 只能写在事件图表里 发送Post请求 只能写在事件图表里 设置…

【读代码】BAGEL:统一多模态理解与生成的模型

一、项目概览 1.1 核心定位 BAGEL是字节跳动推出的开源多模态基础模型,具有70亿激活参数(140亿总参数)。该模型在统一架构下实现了三大核心能力: 多模态理解:在MME、MMBench等9大评测基准中超越Qwen2.5-VL等主流模型文本生成图像:生成质量媲美SD3等专业生成模型智能图像…