当前位置: 首页 > news >正文

(delphi11最新学习资料) Object Pascal 学习笔记---第6章第3节(传递字符串作为参数)

6.3 字符串数据类型

Object Pascal 中的字符串数据类型比简单的字符数组复杂得多,其功能远远超出了大多数编程语言为类似数据类型提供的功能。在本节中,我将介绍这种数据类型背后的关键概念;在接下来的章节中,我们将更详细地探讨其中的一些特性。

​ 在以下要点中,我总结了理解语言中字符串工作原理的关键概念(请记住,即使不了解这些概念,您也可以使用字符串,因为字符串的内部行为是非常透明的):

  • 字符串类型的数据在堆上动态分配。字符串变量只是对实际数据的引用。不必过多担心这一点,因为编译器会透明处理这个问题。与动态数组一样,当声明新字符串时,该字符串是空的。
  • 尽管可以以多种方式向字符串分配数据,但还可以通过调用SetLength函数来分配特定数量的内存。参数是字符串应该能够容纳的字符数(每个2字节)。扩展字符串时,现有数据将被保留(但可能会被移动到新的物理内存位置)。而缩小字符串时,部分内容可能会丢失。很少有必要设置字符串的长度。唯一常见的情况是需要将字符串缓冲区传递给指定平台的操作系统函数。。
  • 如果要增加字符串在内存中的大小(通过与另一个字符串连接),但相邻内存中有其他内容,则字符串不能在相同的内存位置中增长,因此必须在另一个位置制作字符串的完整副本。
  • 要清除字符串,不要对引用本身进行操作,只需将其设置为空字符串,即’ ',或者可以使用相对应的Empty常量。
  • 根据Object Pascal的规则,字符串的长度(可以通过调用Length获得)是有效元素的数量,而不是分配的元素的数量。与C不同,C具有字符串终止符(#0)的概念,从早期开始,所有版本的 Pascal 都倾向于使用特定的内存区域(字符串的一部分)来存储实际的长度信息。不过,有时你会发现字符串也有结束符。
  • Object Pascal 字符串使用引用计数机制,该机制会记录有多少个字符串变量在内存中引用给定的字符串。当字符串不再被使用时,即不再有字符串变量引用数据且引用计数为零时,引用计数将释放内存。
  • 字符串使用写时复制技术,非常高效。当将字符串赋值给另一个字符串或将其传递给例程的字符串参数时,不会复制数据,并且引用计数会增加。但是,如果更改其中一个引用的内容,系统将首先制作副本,然后仅修改该副本,其他引用保持不变。
  • 使用字符串连接向现有字符串添加内容的速度通常非常快,而且没有明显的缺点。虽然还有其他方法,但字符串连接既快速又强大。这在当今许多编程语言中并非如此。

​ 我想这样的描述可能会让人有点困惑,所以让我们来看看字符串在实际中的使用。稍后,我将通过一个演示来展示上述的一些操作,包括引用计数和写时复制。不过,在此之前,让我先回到字符串辅助操作和其他一些管理字符串的基本 RTL 函数上来。

​ 首先,让我们根据实际代码测验一下前面列表中的结论。由于字符串操作非常完美,除非您开始查看字符串的内存结构(在本书的较晚部分我会这样做,因为这在目前的阶段过于高级),否则很难完全理解发生了什么。因此,让我们从 Strings101 示例中提取的一些简单字符串操作开始:

varString1, String2: string;
beginString1 := 'Hello world';String2 := String1;Show('1: ' + String1);Show('2: ' + String2);String2 := String2 + ', again';Show('1: ' + String1);Show('2: ' + String2);
end;

当执行此第一个代码段时,如果将两个字符串赋值相同的内容,修改其中一个不会影响另一个。也就是说,String1不受对String2的更改的影响:

1: Hello world
2: Hello world
1: Hello world
2: Hello world, again

不过,在后面的演示中我们会更好地了解到,初始赋值并不会导致字符串的完全复制,复制是延迟的,这种特性被称为写时复制(copy-on-write)。

​ 另一个需要了解的重要特性是如何管理长度。如果询问字符串的长度,就会得到实际值(实际值存储在字符串元数据中,因此操作速度非常快)。但如果调用 SetLength,则需要分配内存,而内存通常不会被初始化。这通常用于将字符串作为缓冲区传递给外部系统函数。

​ 如果需要一个空字符串,可以使用伪构造函数Create。最后,您可以使用SetLength修剪字符串。以下代码演示了所有这些情况:

varString1: string;
beginString1 := 'Hello world';Show(String1);Show('Length: ' + String1.Length.ToString);SetLength(String1, 100);Show(String1);Show('Length: ' + String1.Length.ToString);String1 := 'Hello world';Show(String1);Show('Length: ' + String1.Length.ToString);String1 := String1 + string.Create(' ', 100);SetLength(String1, 100);Show(String1);Show('Length: ' + String1.Length.ToString);
end;

输出大致如下:

Hello world
Length: 11
֐~ֳ~ו~׵~؛~ف~٦~ڋ~گ~ۓ~~Helloworld~̆~~̫ ͌~ʹ~Η~υ~ϧ~Ј~Щ~ы~ѭ~ҏ~ұ~Ә~Ӽ~ԟ~Շ~հ
~〈~⌇~۵~ܚ~ܼ~ݡ~~ރ~ޤ~ߊ~߰~֐~֐~֐~֐~ࢮ~ ~֐~ Length: 100
Hello world
Length: 11
Hello world
Length: 100

​ 节要强调的第三个概念是空字符串。当字符串的内容是空字符串时,它就是空字符串。无论是赋值还是测试,都可以使用两个连续的引号或特定函数:

varString1: string;
beginString1 := 'Hello world';if String1 = '' thenShow('Empty')elseShow('Not empty');String1 := ''; // 或者 String1.Empty;if String1.IsEmpty thenShow('Empty')elseShow('Not empty');
end;

上述代码生成这个简单的输出:

Not empty
Empty
6.3.1 传递字符串作为参数

​ 正如我已经解释过的,如果你将一个字符串赋值给另一个字符串,你只是复制了一个引用,而内存中的实际字符串并没有被复制。但是,如果你编写的代码改变了该字符串,那么字符串就会首先被复制(仅在该点),然后被修改。

​ 将字符串作为参数传递给函数或过程时,也会发生类似的情况。默认情况下,你会获得一个新的引用,如果你在函数中修改了字符串,这并不会影响原始字符串。如果想获得不同的行为,即在函数中修改原始字符串,则需要使用 var 关键字通过引用传递字符串(就像大多数其他简单数据类型和托管数据类型一样)。

​ 但如果不想修改作为参数传递的字符串呢?在这种情况下,可以对参数使用 const 修饰符进行优化。这样做意味着编译器不会让你在函数或过程中修改字符串,但也会因此优化参数传递操作。事实上,const 字符串不需要函数在开始时增加字符串引用计数,也不需要在结束时减少字符串引用计数,因为函数知道字符串不能被修改。

​ 虽然字符串管理的例程非常快,但执行数千或数百万次也会给程序增加一点开销。这就是为什么在函数不需要修改字符串参数值的情况下,建议将字符串作为常量传递(尽管下面的注释中提到了潜在存在的问题)。

​ 用编码术语来说,这是三个以不同方式传递字符串参数的过程的声明:

procedure ShowMsg1(Str: string);
procedure ShowMsg2(var Str: string);
procedure ShowMsg3(const Str: string);

注解:近年来,除非函数和方法需要对字符串进行修改,否则强烈所有字符串参数都应作为常量传递。但有一个非常重要的注意事项:对于常量字符串参数,编译器获取字符串引用后不会对其进行 “管理”(不进行引用计数等),而是将其视为指向内存位置的指针。编译器会正确检查例程的代码是否不会更改字符串参数。但是,编译器无法控制参数所指向的原始字符串会发生什么变化。

​ 对该字符串的更改会影响其内存布局和位置,这一点普通字符串参数可以处理(具有多个引用的字符串会自动执行写时复制操作),而常量字符串参数则会受到这些更改的影响。换句话说,对原始字符串的更改会使引用它的常量参数失效,使用它很可能会导致内存访问错误。

相关文章:

(delphi11最新学习资料) Object Pascal 学习笔记---第6章第3节(传递字符串作为参数)

6.3 字符串数据类型 ​ Object Pascal 中的字符串数据类型比简单的字符数组复杂得多,其功能远远超出了大多数编程语言为类似数据类型提供的功能。在本节中,我将介绍这种数据类型背后的关键概念;在接下来的章节中,我们将更详细地探…...

k8s节点负载使用情况分析命令kubectl describe node [node-name]

1.到任意安装了kubectl节点命令的节点上执行kubectl describe node [node-name] 上面的Requests最小分配 Limits最大分配是所有pod之和,最小分配之和不能超过服务器实际参数,否则新的pod会因为资源不够起不来,最大分配是预设之和&#xff0…...

自动驾驶加速落地,激光雷达放量可期(上)

1 激光雷达应用广泛,汽车有望成最大催化 激光雷达(LiDAR)是一种主动遥感技术,通过测定传感器发出的激光在传感器与目标物体之间的传播距离,来分析目标地物表面的反射能量大小、反射波谱的幅度、频率和相位等信息&#…...

变量的间接引用

场景: 如果第一个变量的值是第二个变量的名字,我们能够从第一个变量中取得第二个变量的值吗?例如,如果aztj且ztjz,那么我们能够通过引用变量a来获得值z吗?答案是可以,它被称为间接引用&#xf…...

学习JAVA的第六天(基础)

目录 集合 集合和数组的对比 ArrayList成员方法 ArrayList成员方法代码展示 练习 集合的遍历01之字符串 集合的遍历02之数字 集合的遍历03之学生对象 集合 集合和数组的对比 从长度维度来看 数组长度固定 集合长度可变从存储类型维度来看 数组可以存放基本数据类型和…...

LeetCode 2673.使二叉树所有路径值相等的最小代价:自顶向下的DFS 或 自底向上的递推

【LetMeFly】2673.使二叉树所有路径值相等的最小代价:自顶向下的DFS 或 自底向上的递推 力扣题目链接:https://leetcode.cn/problems/make-costs-of-paths-equal-in-a-binary-tree/ 给你一个整数 n 表示一棵 满二叉树 里面节点的数目,节点编…...

9、电源管理入门之CPU Idle

目录 1. CPU Idle有什么用? 2. CPU Idle整体框架 3. Idle状态判断 3. cpuidle core 4. 注册初始化 4.1 cpuidle governor注册 4.2 cpuidle driver注册 4.3 cpuidle device注册 5. cpuidle触发流程 关于Linux的很多知识其实网上的资料非常的多,但是也有些问题: 有时…...

uniapp的扩展组件uni-popup 弹出层自动打开

我的需求是在页面加载完之后自动打开弹窗,自动打开只能写在onReady 或 mounted 生命周期内,这是这个组件的规定: 如果想在页面渲染完毕后就打开 uni-popup ,请在 onReady 或 mounted 生命周期内调用,确保组件渲染完毕…...

二、mysql常用函数

目录 一、Mysql数值型函数 二、Mysql字符串函数 三、Mysql日期和时间函数 四、Mysql聚合函数 五、Mysql流程控制函数 六、其他函数 一、Mysql数值型函数 函数名称 作用 abc 求绝对值 sqrt 求二次方根 mod 求余数 ceil 和 ceiling 功能一样,都是返回不小…...

【Redis | 第一篇】快速了解Redis

文章目录 1.快速了解Redis1.1简介1.2与其他key-value存储的不同处1.3Redis安装——Windows环境1.3.1下载redis1.3.2启动redis1.3.3进入redis客户端1.3.4修改配置 1.4Redis安装——Linux环境1.4.1安装命令1.4.2启动redis1.4.3进入redis客户端 1.5配置修改1.6小结 1.快速了解Redi…...

Vim 模式切换 | 命令集

Vim 模式切换 | 命令集 vim 主要模式及切换一、正常/普通/命令模式1 光标相关操作命令集1.1 光标移动1.2 文字删除1.3 粘贴和复制1.4 撤销1.5 字符更改 二、插入模式2.1 插入模式和命令行模式相互切换 三、末行模式2.1 末行模式和命令行模式相互切换2.2 末行模式相关命令集 四、…...

广和通5G智能模组SC171支持Android、Linux和Windows系统,拓宽智能物联网应用

世界移动通信大会2024期间,广和通宣布:5G智能模组SC171除支持Android操作系统外,还兼容Linux和Windows系统,帮助更多智能终端客户快速迭代产品,拓宽智能化应用覆盖范围。 广和通SC171系列基于高通QCM6490物联网解决方案…...

【51单片机】红外遥控红外遥控电机调速(江科大)

1.红外遥控简介 红外遥控是利用红外光进行通信的设备,由红外LED将调制后的信号发出,由专用的红外接收头进行解调输出 通信方式:单工,异步 红外LED波长:940nm 通信协议标准:NEC标准 2.硬件电路 红外发送部分 IN高电平时,LED不亮,IN低电平时&…...

kubesphere jenkins 流水线 未运行(解决方案)

场景: 在kubesphere 中运行 流水线 devops 结果,显示未运行 但是用 admin 账户是可以运行成功的。 问题解决 1- 查日志: 然后 Caused: org.acegisecurity.userdetails.UsernameNotFoundException: org.springframework.security.core.…...

如何保护服务器的安全

互联网的迅速发展,让很多企业都很重视网络技术的使用,但是网络的传播速度比较快,同时容易造成数据、隐私方面的泄露现在每个企业基本有自己的服务器。有几点需要注意,可以参考: 1.基础密码安全 最基本的安全就是密码安…...

Python使用HDL 模拟器实现 FPGA 板卡的仿真验证

Python 结合 HDL 模拟器实现 FPGA 板卡的仿真验证,您可以借助一些开源工具和库来实现这一目的。下面我将为您介绍一种常用的方法,使用 Python 结合 Verilog 模拟器和 FPGA 开发工具进行仿真验证。 ### 步骤概述 1. **编写 Verilog 设计**:首…...

vue中 input disable后无法触发点击事件

问题:input标签为disabled后,点击事项无效;当点击文字**“请选择”**时无法触发点击事件,其父标签的其余位置均可触发 解决:只需要在input标签中添加 style“pointer-events:none” 即可 pointer-events: none 作用是…...

实战一个 Jenkins 构建 CI/CD流水线 的简单配置过程哈

引言:上一期我们讲述了gitlabCI/CD工具的介绍,工具之争,本期我们介绍Jenkins CI/CD 目录 一、Jenkins介绍 1、Jenkins概念 2、Jenkins目的 3、特性 4、产品发布流程 二、安装Jenkins 1、安装JDK 2、安装Jenkins 1、上传压缩包 2、…...

【InternLM 实战营笔记】大模型评测

随着人工智能技术的快速发展, 大规模预训练自然语言模型成为了研究热点和关注焦点。OpenAI于2018年提出了第一代GPT模型,开辟了自然语言模型生成式预训练的路线。沿着这条路线,随后又陆续发布了GPT-2和GPT-3模型。与此同时,谷歌也…...

数据卷(Data Volumes) 自定义镜像(dockerfile)

目录 一. 数据卷(Data Volumes) 1.1 什么是数据卷 1.2 为什么需要数据卷 1.3 数据卷的作用 1.4 数据卷的使用 二. 自定义镜像(dockerfile) 2.1 什么是dockerfile 2.2 自定义centos 2.3 自定义tomcat 一. 数据卷(Data…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...