为什么要有指针和引用类型?
简单说,是为了必要的,且很基础的表达能力 (描述能力)。
0. 数据四要素:名、值、址、型
指针、引用的基础,就是在描述一个数据时,除了这个数据的“值”以外,引入了这个数据的“地址”(以下也会简称“址”),即数据在哪个位置上。
进一步理解,数据数据的“地址”,表达的是这个数据的“实体”,数据的“值”,表达的是数据的“表象”。
就好比说,你老婆的漂亮值是 100,我老婆的也是,但这两个100并不是在描述同一个实体。
相同的值,可能在表达不同的类型的数据,所以,在值、址之外,数据还需要一个“类型”(以下也会简称“型”)。
最后,除了“值”、“址”、“型”为了方便我们在代码中指定某个数据,代码中的多数据,还有一个属性“名字”比如变量或常量的名字(以下也会简称“名”)。有名数据通常就是变量、常量,无名的数据就是“字面量”。
编译型的代码,在编译之后,“名”这个属性通常没有一直存在的必要性(哪怕有带反射),因为程序绝大多数情况下,可以通过地址来精确指代一个数据。
类似的,“型”在代码表达中极其重要,但在在编译之后的程序里,必要性也不高。
1. 猥琐语言的进化史
好,同学们,下面我来举一个语言的例子,让大家肉眼观察这门语言是如何进化出“指针、引用”的。首先我们需要从基础的,数据据的名、值、址的理解开始。
我们即时发明的一种程序语言,名为 “猥琐”计算机语言,有时也简称WS。
1.1 从字面数据开始
让我们WS语言开始写代码:
18
18
由于网上竟然还没有支持猥琐语言的高亮脚本,所以以下只好委屈 C、C++、Go 等语言了,我们的代码标记为它们以获得高亮。
代码中出现两个18!问题马上来了:这两个18表达的是同一个意思吗?如果是同一个意思?那为什么要有两个18?
1.2 上帝说:要有类型……
也就是说,现在,两个数据都有“值”,但是,它们在表达什么?它们没有类型吗?让我们查询一下WS语言手册有什么内置类型……
哇!好棒,内置类型竟然有 年龄、长度、胸围……
我们选长度:
18 : 长度 // WS语言语法: 值 : 类型
18 : 长度
有“值”有“型”,但还不够——
- 它们分别是什么东西的长度?
- 假设代码中有很多地方需要使用到这个长度,难道一直写 18 ,万一哪天要改成 17呢?
- 如果就是写 18,那为什么要定义两个18?只有一个就够了呀?
好吧,是时候让“名”登场了:
JJ长 = 18 : 长度 // WS是一门国际化语言,支持数据使用汉字作名字
JJ长 = 18 : 长度
1.3 不要重名,不要重名!
等等!!!一前一后两个数据的“名”竟然完全同名!WS语言制定者,你们太不专业了!
- WS语言制定者:名字相同有什么不合理吗?现实生活中,你老婆叫王大锤,我老婆也叫王大锤啊!
- WS语言用户:那我们怎么区分哪个是哪个啊!!!!
- WS语言制定者:当然是看数据的地址,也就实体啊!地址不同,实体就不同;在你家床上睡的王大锤是你老婆,在我家床上睡的是我老婆啊?有什么区分困难吗?
- WS语言使用者:可是上面代码中,没有体现数据的地址属性啊。
哦!也对。计算机语言中的数据,是如何体现它们(存放在内存中的)地址不同呢? 让我们借鉴一下其它语言吧,包含但不限于:C、C++、C#、Java、Go……
借鉴完毕,原来这么简单呀:就是不直接在代码使用地址表达数据,但是在有需要时,可以通过数据“名字”来映射到数据的“地址”。
"有需要时" 是重点。说明见后。
这么说,数据的名字,还真是不要允许同名的好,万一要同名的话,两个数据就必须处于不同的上下文中……比如复合语句作用域,比如名字空间……
算了算了,猥琐语言主打简洁而猥琐,就让我们简(猥)单(琐)地规定所有变量不允许同名吧!
我的JJ长 = 18 : 长度
你的JJ长 = 18 : 长度
好,现在我们拥有两个数据:我的JJ长,和你的JJ长。核心问题来了:这两个数据除了名字不一样以外,它们“型”相同、“值”相同,所以,它们是同一个数据吗?
1.4 地址不同,才是真的不同
当然不是!我的JJ在我这里,你的JJ在你这里。
同学: 老师,偶尔也会在王大锤(们)那里。
老师:你们在说什么?
也就是说,“我的JJ长”和“你的JJ长”,值相同,型相同,名不同,址不同。
“址”肯定代表一个数据实体。而“名”,如前所述,主要是给程序员使用的,它有时代表“值”,有时代表“址”。
[重点]
- 有的计算机语言,在某些上下文可以自行决定这个名字表达的是“值”,还是“址”,即左值右值之分,在无法自动区分的情况下,当需要从名到址转换时,采用一个特殊的操作来表达,比如C、Go、C++中用特定的“取址操作符”(通常是 &) ;
- 而有的语言,几乎都可以纯粹通过上下文来判断,比如 Java。这类语言通常就是把“型”和“名”的作用做了硬性绑定:某些“型”的数据,它的“名”只表达值,某些“型”的数据,它的“名”可以表达“址”。
1.5 当数据需要传递……
猥琐语言少不了有函数。现在我们就需要一个叫“增大术”的函数,长这样:
func 增大术 ( jjl : 长度 ) -> boolean {if jjl <= 5 :输出 "根基太小了,恕本医师无能为力"return falseif jjl >= 30 :输出 "请不要过份追求肉体上的尺寸!内心的强大才是真正的强大!"return falsejjl++return true
}
可以把“增长术”这个函数,理解为一场“手术”,所以它返回手术是否成功,而不是返回新长度;同时,它动刀的是原有长度,同样不是返回新长度。
由此,我们预期:
你的JJ长 = 18 : 长度
增大术 (你的JJ长)输出 你的JJ长 // 应该得到 19
但是,问题来了, 代码中第二行的, 传入 增大术函数的 你的JJ长 ,现在这个“名”,它表达的是对应数据的“值(表象)”?还是“址”(实体)呢?
显然得是后者!显然没有哪一位大神医师,能通过计算一个18+1得到19,就让你身上的某个东西从18变成19,你必须掏出实体并且放到手术台上啊!
猥琐语言使用者(医生角色):“来,这位患者,请把“你的JJ长”的实体,传送过来,摆在这里,我要动刀(修改)了”
猥琐语言制定者:“等一下,让我想想……”
没错,是时候想一想WS语言的下一步发展了。如前所述,我们有两个选择:
- 通过增加明确的表达方式(比如一个符号),来区分一个数据的名字是“值”或是“址”(指针);
- 通过将“型”和“名”的作用硬性绑定,让特定的某些类型的数据,名字即可表达数据的“址”(常被称为“引用类型”),而另一些类型的数据,名字就永远只能表达“值”(常被称为“值类型”)
选择1,是C++的路;选择2,是Java的路。
选择在1和2之间来回混的,是 go语言的路。
无论何种选择,反正,指针或引用,就这么引入了。让我们都给个例子:
(一)、 C++风格
func 增大术 ( jjl : *长度 ) -> boolean { // 注意,现在入参的类型是 “ *长度 ”...
}你的JJ长 = 18 : 长度
增大术 ( & 你的JJ长) // 注意多了一个取址符 & 输出 你的JJ长 // 得到 19
(二)、Java风格
先规定 长度 是值类型(不能表达址),再特意搞出一种对应类型,叫 “长度的包装箱”,是引用类型:
func 增大术 ( jjl : 长度的包装箱 ) -> boolean { // 注意,现在入参的类型是 “长度的包装箱”...
}你的JJ长 = 18 : 长度
放在这个箱子里的你的JJ长 = 装箱操作(你的JJ长) // 注意有个装箱操作增大术 ( 放在这个箱子里的你的JJ长 ) // 注意实参现在放在箱子里再传过去……你的JJ长 = 拆箱操作(放在这个箱子里的你的JJ长) // 注意这里拆快递了输出 你的JJ长 // 得到 19
2 最后,回到问题
指针和引用当然还有别的用处,且有既有紧密关系又有重大区别。但都不是问题“为什么要有指针和引用类型”的重点了,因为本文已经讲了“为什么需要指针或引用”的一个必要条件。
相关文章:
为什么要有指针和引用类型?
简单说,是为了必要的,且很基础的表达能力 (描述能力)。 0. 数据四要素:名、值、址、型 指针、引用的基础,就是在描述一个数据时,除了这个数据的“值”以外,引入了这个数据的“地址…...
vivado INTERNAL_VREF
内部 具有差分输入缓冲器的单端I/O标准需要输入参考 电压(VREF)。当I/O组中需要VREF时,您可以使用专用VREF 引脚作为外部VREF电源,或使用INTERNAL_VREF内部生成的VREF 属性,或者对于UltraScale设备上的HP I/O组&#x…...

VScode通过Graphviz插件和dot文件绘制层次图,导出svg
1、安装插件 在VScode中安装Graphviz Interactive Preview插件,参考。 2、创建dot文件 在本地创建一个后缀为dot的文件,如test.dot,并写入以下内容: digraph testGraph {label "层次图";node [shape square; widt…...

MMCV 核心组件分析(一):整体概述
概述 MMCV 是计算机视觉研究的基础库,并提供以下功能。...

阵列信号处理学习笔记(一)--阵列信号处理定义
阵列信号 阵列信号处理学习笔记(一)–阵列信号处理定义 阵列信号处理学习笔记(二)–空域滤波基本原理 文章目录 阵列信号前言一、阵列信号处理定义1.1 信号1.2 阵列 二、雷达数据中哪些属于空间采样总结 前言 MOOC 阵列信号处理…...

[HTML]一文掌握
背景知识 主流浏览器 浏览器是展示和运行网页的平台, 常见的五大浏览器有 IE浏览器、火狐浏览器(Firefox)、谷歌浏览器(Chrome)、Safari浏览器、欧朋浏览器(Opera) 渲染引擎 浏览器解析代码渲…...

ABAP使用SQL直接更新数据库与使用IN UPDATE TASK的区别
1. 背景 刚接触ABAP的小伙伴常常会有这样的疑问,为什么不直接使用Open SQL直接更新数据库,而要把对DB的操作封装到IN UPDATE TASK中呢? 对于这个问题,比较常见的解释是,IN UPDATE TASK的方式会保证数据更新的一致性。…...

Android GWP-Asan使用与实现原理
目录 一、 背景 二、GWP-Asan介绍 2.1 什么是GWP-ASan 2.2 GWP-Asan与其他几类工具对比 2.3 GWP-ASan与其它内存分配器的兼容性 三、GWP-Asan如何使用 3.1 app进程 3.2 native进程 四、GWP-Asan实现原理 4.1 进程启用GWP-Asan 4.2 初始化 4.3 内存分配 4.3.1 内存…...
SpringBoot 跨域请求处理全攻略:从原理到实践
文章目录 SpringBoot 如何处理跨域请求?你能说出几种方法?跨域请求概述跨域解决方案1. 使用CrossOrigin注解2. 使用WebMvcConfigurer配置类3. 使用过滤器(Filter)4. 使用Spring Security处理CORS5.使用Spring Cloud Gateway处理CO…...

vulnhub——Ai-Web1靶机渗透
Ai-Web1靶机渗透 靶机下载: 官网地址:https://www.vulnhub.com/entry/ai-web-1,353/ 攻击机:kali2024 一、信息收集 发下目标主机的IP为:192.168.201.141 用nmap工具扫描一下对方主机和服务 发现他打开了80端口 发现搜不到于是…...
sqlalchemy事件监听
sqlalchemy事件监听 SQLAlchemy 中的事件监听允许您在特定事件发生时执行自定义的 Python 代码。这些事件可以是与ORM(对象关系映射)或核心组件相关的操作,比如表、类、会话或事务的插入、更新、删除等操作。通过事件监听,您可以实现日志记录、审计或执行业务规则等功能。…...

【Django+Vue3 线上教育平台项目实战】Celery赋能:优化订单超时处理与自动化定时任务调度
文章目录 前言⭐✨💫🔥📖一、Celery⭐1.基本概念及介绍:✨2.使用步骤💫 二、订单超时 取消订单(Celery)🔥具体实现流程📖 前言⭐✨💫🔥📖 在构建复…...
CSS3 教程
CSS3 教程 引言 CSS3,即层叠样式表的第三代,是网页设计和开发中不可或缺的技术之一。它为HTML元素提供了丰富的样式定义,使得网页不仅内容丰富,而且外观美观、交互性强。本教程将详细介绍CSS3的基础知识、高级特性以及最佳实践&…...

树与二叉树学习笔记
树与二叉树 计算机中的树树的概念树的类型 什么是二叉树二叉树:定义与特点二叉树:前序、中序、后序遍历二叉树:深度、广度优先遍历二叉树:线索化二叉树:序列化与反序列化 haffman树平均编码长度构建haffman树haffman树…...

消费金融系统开发回忆录
架构设计图 整个支付链路上的功能 支付系统应该有:账户管理、渠道管理、支付管理、对账管理、清算管理、结算管理 一笔支付订单,在支付系统侧就是要记录清楚,谁发起的、对哪个商品进行支付、通过哪个渠道支付、支付时间、支付结果等…...

org.springframework.context.ApplicationContext发送消息
1、创建消息的实体类 package com.demo;/*** 监听的实体类**/ public class EventMessage {private String name;public EventMessage(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;} }2、创建消…...
Java8-21新特性
简介 由于Java官方最近更新越来越频繁,而长期支持维护的版本LTS版每隔几年才推出一个,大规模商用的JDK只可能选择LTS版,因此这里只简单记录JDK8,11,17,21。 jdk8 Lambda表达式: Lambda表达式…...
NodeJS系列面试题
大家好,我是有用就扩散,有用就点赞。 有没有写过Koa中间件,说一下中间件原理,介绍下自己写过的中间件 koa本来就是一个轻量级框架,本身支持的功能并不多,功能都是通过中间件来实现不同的需求。开发者可以通…...

QXlsx读写excel
QXlsx读写excel 安装 QXlsx使用 qmake使用 CMake 基本用法1. 写入 Excel 文件2. 读取 Excel 文件 详细用法1. 设置单元格样式2. 合并单元格3. 创建图表4. 设置列宽和行高 完整示例 QXlsx 是一个用于在 Qt 应用中读写 Excel 文件的第三方库。它提供了丰富的 API,可以…...

昇思25天学习打卡营第13天 | mindspore 实现 ShuffleNet 图像分类
1. 背景: 使用 mindspore 学习神经网络,打卡第 13 天;主要内容也依据 mindspore 的学习记录。 2. 迁移学习介绍: mindspore 实现 ShuffleNet 图像分类; ShuffleNet 基本介绍: ShuffleNetV1 是旷视科技提…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...