一文彻底理解C语言中的指针

news2025/1/12 6:08:10

假定给你一块非常小的内存,这块内存只有8字节,这里也没有高级语言,没有操作系统,你操作的数据单位是单个字节,你该怎样读写这块内存呢?

注意这里的限定,再读一遍,没有高级语言,没有操作系统,在这样的限制之下,你必须直面内存读写的本质。这个本质是什么呢?本质是你需要意识到内存就是一个一个装有字节的小盒子,这些小盒子从0到N编好了序号。这时如果你想计算1+2,那么你必须先把1和2分别放到两个小盒子中,假设我们使用Store指令,把数字1放到第6号小盒子,那么用指令表示就是这样:

store 1 6

注意看这条指令,这里出现了两个数字:1和6,虽然都是数字,但这两个数字的含义是不同的,一个代表数值,一个代表内存地址。与写对应的是读,假设我们使用load指令,就像这样:

load r1 6

现在依然有一个问题,这条指令到底是数字6写入r1寄存器还是把第6号小盒子中装的数字写入r1寄存器?可以看到,数字在这里是有歧义的,它既可以表示数值也可以表示地址,为加以区分我们需要给数字添加一个标识,比如对于前面加上$符号的就表示数值,否则就是地址:

store $1 6
load r1 6

这样就不会有歧义了。现在第6号内存中装入了数值1:

即地址6代表数字1:

地址6 -> 数字1

但“地址6”对人类来说太不友好了,人类更喜欢代号,也就是起名字,假设我们给“地址6”换一个名字,叫做a,a代表的就是地址6,a中存储的值就是1,用人类在代数中直观的表示就是:

a = 1

就这样所谓的变量一词诞生了。

我们可以看到,从表面上看变量a等价于数值1,但背后还隐藏着一个重要的信息,那就是变量a代表的数字1存储在第6号内存地址上,即变量a或者说符号a背后的含义是:

  1. 表示数值1
  2. 该数值存储在第6号内存地址

到现在为止第2个信息好像不太重要,先不用管它。既然有变量a,就会有变量b,如果有这样一个表示:

b = a

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linuxc/c++高级开发【直播公开课】

零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

把a的值给到b,这个赋值在内存中该怎么表示呢?很简单,我们为变量b也找一个小盒子,假设变量b放在第2号小盒子上:

可以看到,我们完全copy了一份变量a的数据。现在有了变量,接下来让我们升级一下,假设变量a不仅仅可以表示占用1个字节的数据,也可以表示占用任意多内存的数据,就像这样:

现在变量a占据5个字节,足足占用了整个内存的一大半空间,此时如果我们依然想要表示b = a会怎样呢?如果你依然采用copy 的方法会发现我们的内存空间已经不够用了,因为整个内存大小就8字节,采用copy的方法仅这两个变量代表的数据就将占据10字节。怎么办呢?不要忘了变量a背后可是有两个含义的,再让我们看一下:

  1. 表示数值1
  2. 该数值存储在第6号内存地址

重点看一下第2个含义,这个含义告诉我们什么呢?它告诉我们不管一个变量占据多少内存空间,我们总可以通过它在内存中地址找到该数据,而内存地址仅仅就是一个数字,这个数字和该数据占用空间的大小无关。啊哈,现在变量的第2个含义终于排上用场了,如果我们想用变量b也去指代变量a,干嘛非要直接copy一份数据呢?直接使用地址就不好了,就像这样:

变量a在内存中地址为3,因此变量b中我们可以仅仅存储3这个数字即可。现在变量b就开始变得非常有趣了。首先变量b没什么特殊的,只不过变量b存储的东西我们不可以按照数值来解释,而是必须按照地址来解释。当一个变量不仅仅可以用来保存数值也可以保存内存地址时,指针诞生了。有很多资料仅仅说指针就是地址,但小风哥认为这是一种偷懒的解释,仅仅停留在汇编层面来理解,有失偏颇,在高级语言中,指针首先是一个变量,只不过这个变量保存的恰好是地址而已,指针是内存地址的更高一级抽象。如果仅仅把指针理解为内存地址的话你就必须知道所谓的间接寻址。这是什么意思呢?如果使用汇编语言来加载变量a的值该怎么写呢?

load r1 1

想一想,这是不是会有问题,因此这样的话该指令会把数值3加载到r1寄存器中,然而我们想要把内存地址1中保存的数值也解释为内存地址,这时必须为1再次添加一个标识,比如@:

load r1 @1

这时该指令会首先把内存地址1中保存的值读取出来发现是3,然后再次把3按照内存地址进行解释,3指向的数据就是变了a:

地址1 -> 地址3 -> 数据a

这就是所谓的间接寻址,Indirect addressing,在汇编语言下你必须能意识到这一层间接寻址,因为在汇编语言中是没有变量这个概念的。然而高级语言则不同,这里有变量的概念,此时地址1代表变量b,但使用变量的一个好处就在于很多情况下我们只需要关心其第一个含义,也就是说我们只需要关心变量b中保存了地址3,而不需要关心变量b到底存储在哪里,这样使用变量b时我们就不需在大脑里想一圈间接寻址这一问题了,在程序员的大脑里变量b直接指向数据a:

b -> 数据a

再来对比一下:

地址1 -> 地址3 -> 数据a   # 汇编语言层面
变量b -> 数据a            # 高级语言层面

这就是为什么我说指针其实是内存地址的更高级抽象,这个抽象的目的就在于屏蔽间接寻址。当变量不仅仅可以存值也可以存放地址时,一个全新的时代到来了:看似松散的内存在内部竟然可以通过指针组织起来,同时这也让程序直接处理复杂的数据结构成为可能,比如就像下图这样:

这就是所谓的链表了。

指针这个概念首次出现在 PL/I 语言中,当时是为了增加链表处理能力,大家不要以为链表这种数据结构是非常司空见惯的,这在1964年左右并不是一件容易的事情,值得一提的是,Multics操作系统就是 PL/I 语言实现的,这也是第一个用高级语言实现的操作系统,然而Multics操作系统在商业上并不成功,参与该项目的Ken Thompson, Dennis Ritchie后来决定自己写一个更简单的,Unix以及C语言诞生了,或许是在开发Multic时见识到了PL/I语言中指针的威力,C语言中也有指针的概念。

原文作者:码农的荒岛求生

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

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

相关文章

rabbitmq-3.8.15集群、集群镜像模式安装部署

目录 一、环境 1、映射、域名、三墙 2、Erlang和socat安装(三台服务器都实行) 二、部署三台rabbitmq-3.8.15实例 1、rabbitmq官网下载地址 : 2、解压rabbitmq 3、添加系统变量 4、启动web插件、启动rabbitmq 5、在rabbitmq1上添加用…

(PyTorch)PyTorch中的常见运算(*、@、Mul、Matmul)

1. 矩阵与标量 矩阵(张量)每一个元素与标量进行操作。 import torch a torch.tensor([1,2]) print(a1) >>> tensor([2, 3]) 2. 哈达玛积(Mul) 两个相同尺寸的张量相乘,然后对应元素的相乘就是这个哈达玛…

常见的芯片封装技术

两边出pin的封装 1、DIP封装 DIP封装(Dual In-line Package),也叫双列直插式封装技术,指采用双列直插形式封装的集成电路芯片,绝大多数中小规模集成电路均采用这种封装形式,其引脚数一般不超过100。DIP封装…

windows11录屏功能详解,记录你的精彩时刻

windows 11是微软最新推出的操作系统版本,拥有很多简单便捷的功能,包括内置的录屏工具,让用户可以轻松地录制屏幕内容。但是很多人不了解windows11录屏功能,本文将详细介绍windows 11录屏的三个方法,以及它们的优势和适…

HTTP图解基础知识

书:图解HTTP;分享书中学到的东西,内容很多,极具可玩性关键字:http,cookie,状态,头部字段,缓存,Etag 参考示例:https://zhuanlan.zhihu.com/p/…

ChatGPT在机器学习中的应用与实践

💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 引言 随着人工智能技术…

【Gan教程 】 什么是变分自动编码器VAE?

名词解释:Variational Autoencoder(VAE) 一、说明 为什么深度学习研究人员和概率机器学习人员在讨论变分自动编码器时会感到困惑?什么是变分自动编码器?为什么围绕这个术语存在不合理的混淆?本文从两个角度…

docker搭建waline评论系统

我这里是给博客网站嵌入评论系统的 1.登录LeanCloud 国际版,没有账号可以注册个 链接:点击跳转 2.新建应用,选择开发版(免费),商用版每个月最低消费5美刀。 3.在设置-应用凭证里面将AppID、AppKey、Maste…

基于springboot+vue校园短期闲置资源置换平台051

大家好✌!我是CZ淡陌。一名专注以理论为基础实战为主的技术博主,将再这里为大家分享优质的实战项目,本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目,希望你能有所收获,少走一些弯路…

YoloV8改进策略:独家原创,LSKA(大可分离核注意力)改进YoloV8,比Transformer更有效,包括论文翻译和实验结果

文章目录 摘要论文:《LSKA(大可分离核注意力):重新思考CNN大核注意力设计》1、简介2、相关工作3、方法4、实验5、消融研究6、与最先进方法的比较7、ViTs和CNNs的鲁棒性评估基准比较8、结论YoloV8官方结果改进一:测试结果摘要 本文给大家带来一种超大核注意力机制的改进方…

FFmpeg编译安装(windows环境)以及在vs2022中调用

文章目录 下载源码环境准备下载msys换源下载依赖源码位置 开始编译编译x264编译ffmpeg 在VS2022写cpp调用ffmpeg 下载源码 直接在官网下载压缩包 这个应该是目前(2023/10/24)最新的一个版本。下载之后是这个样子: 我打算添加外部依赖x264&a…

应用系统集成-概述

应用系统集成-概述 随着网络技术的发展和日益增长的软件复杂度,几乎已经不存在一个完全孤立的应用系统了,万物互联在应用层面就是系统互联,应用系统集成成为软件系统架构是需要考虑的核心问题之一。 基本介绍 应用系统集成面临的挑战 所有的…

【网络编程】一文带你搞懂HTTPS协议

文章目录 一、什么是HTTPS协议二、关于加密三、数据摘要 | 数据指纹 | 数字签名四、HTTPS的工作过程探究方案1:只使用对称加密方案2:只使用非对称加密方案3:双方都使用非对称加密方案4:非对称加密 对称加密中间人攻击 五、引入证…

重要功能更新:妙手正式接入SHEIN供货模式(OBM)店铺,赋能卖家把握出海新机遇!

继接入SHEIN平台模式店铺之后,妙手ERP积极响应卖家需求,正式接入SHEIN供货模式(OBM)店铺,并支持产品采集、批量刊登、产品管理等功能,帮助跨境卖家快速上品、高效运营,把握出海新机遇。 SHEIN供…

天软特色因子看板(2023.10 第11期)

该因子看板跟踪天软特色因子A05005(近一日单笔流通金额占比(%),该因子为近一个日单笔流通金额占比因子,用以刻/画股票在收盘时,力资金在总交易金额中所占的比重。 今日为该因子跟踪第11期,跟踪其在SW801130 (申万纺织服装) 中的表…

TwinCAT3 从入门到放弃系列第一篇

TwinCAT3介绍 TwinCAT3是倍福公司基于PC平台和Window操作系统的控制软件。TwinCAT全称是The Windows Control and Automation Technology,基于window的自动化控制技术。 TwinCAT是1995年首次推出市场,现存有TwinCAT2和TwinCAT3两种版本,TC2是…

软件兼容性测试的测试内容有哪些?

软件兼容性测试是软件开发过程中至关重要的一项测试环节。它是指验证软件在不同平台、操作系统、硬件设备或网络环境下的运行情况,以确保软件在各种环境下都能正常工作并与其他软件或系统相互配合。兼容性测试能够帮助开发者发现和修复可能存在的兼容性问题&#xf…

PMP备考|通关宝典

1建立知识全景图 PMBOK 知识框架:五大过程组、十大知识领域、49个过程、132个工具和技术(PMBOK6 P686)。 2项目 项目具有独特性、临时性、渐进明细的特点 组织类型: ▶ 职能型组织:项目联络员,PM职权小…

SSL证书品牌参差不齐?品牌太多不知道怎么选择?

很多采购人认为SSL证书品牌太多,差异很大,安全性能以保证? 错错误,大错特错,其实整个互联网SSL证书绕来绕去就三家!而且是无法替代的! 举列:360搜索表面上起来用的是沃通证书&…

深入理解Java IO流:概念、类型、缓冲与性能

文章目录 什么是I/O流?I/O流的类型字节流(Byte Streams)字符流(Character Streams) 节点流与处理流节点流(Node Streams)处理流(Processing Streams) 带缓冲的I/O流I/O性…