(delphi11最新学习资料) Object Pascal 学习笔记---第5章第1节(静态数组)

第5章 数组与记录

​ 我在第二章介绍数据类型时,提到了Object Pascal中既有内置数据类型又有自定义数据类型。自定义数据类型的一个简单示例是在该章节中介绍的枚举类型。

​ 自定义类型的真正强大体现在更高级的机制中,比如数组、记录和类。在本章中,我将讲述前两个机制,基本上它们的存在可以追溯到 Pascal 的早期定义,但经过多年的改变(现在变得更加强大),它们与早期同名的定义类型几乎没有相似之处。

​ 在本章末尾,我还将简要介绍一些高级的Object Pascal数据类型,比如指针。然而,自定义数据类型的真正威力将在第7章中揭示,届时我们将开始研究类和面向对象编程。

5.1 数组数据类型

​ 数组类型定义了具有特定类型元素的列表。这些列表可以有固定数量的元素(静态数组),也可以有数量可变的元素(动态数组)。通常使用方括号内的索引来访问数组中的一个元素。方括号还可用于定义固定大小数组的数值个数。

Object Pascal 语言支持不同的数组类型,从传统的静态数组到动态数组。建议使用动态数组,特别是在使用移动版本的编译器时。我将首先介绍静态数组,然后重点介绍动态数组。

5.1.1 静态数组

​ 在传统的Pascal语言中,数组是静态的,且大小固定。下面的代码片段就是一个例子,它定义了一个由 24 个整数组成的列表,代表一天 24 小时内的温度:

type
  TDayTemperatures = array[1..24] of Integer;

​ 在这个经典的数组定义中,您可以在方括号内使用子界类型,实际上是用两个序数类型的常量定义了一个新的特定子范围类型。这个子界表示数组的有效索引。由于您同时指定了数组索引的上限和下限,所以数组索引不需要以零为基础,这与C、C++、Java和大多数其他语言的情况不同(尽管在Object Pascal中使用基于零的数组也很常见)。此外,Object Pascal中的静态数组索引既可以是数字,也可以是其他序数类型,如字符、枚举类型等。不过,非整数索引相当少见。

注解:有一些语言,比如JavaScript,大量使用关联数组。Object Pascal数组仅限于序数索引,因此不能直接使用字符串作为索引。RTL 中有现成可用的数据结构可以实现字典和其他类似的数据结构提供此类功能。我将在本书第三部分关于泛型的章节中介绍它们。

​ 由于数组索引基于子界,编译器可以检查其范围。无效的常量子界会导致编译时错误;而在运行时使用的超出范围的索引会导致运行时错误,但前提是必须启用相应的编译器选项。

注解:这是IDE的Project Options对话框的Compiling页面中Runtime errors组的Range checking选项。我在第二章的“子范围类型”一节中已经提到过这个选项。

​ 使用上述数组定义,您可以将TDayTemperatures类型的DayTemp1变量的值设置为以下方式(就像我在ArraysTest示例中所做的那样,以下代码片段从中提取):

type
  TDayTemperatures = array[1..24] of Integer;

var
  DayTemp1: TDayTemperatures;
  
begin
  DayTemp1[1] := 54;
  DayTemp1[2] := 52;
  ...
  DayTemp1[24] := 66;
  // The following line causes:
  // E1012 Constant expression violates subrange bounds
  // DayTemp1[25] := 67;
end;

​ 鉴于数组的性质,对数组进行操作的标准方法是使用 for 循环。下面是一个循环示例,用于显示一天中的所有温度:

var
  I: Integer;

begin
  for I := 1 to 24 do
    Show(I.ToString + ': ' + DayTemp1[I].ToString);
end;

​ 虽然这段代码可以运行,但硬编码数组边界(1和24)并不是一种理想的方式,因为数组定义本身可能会随时间变化,而您可能希望转而使用动态数组。

5.1.2 数组大小和边界

​ 在使用数组时,可以使用标准的 Low 和 High 函数来测试边界,这两个函数会返回下届和上届。在对数组进行操作时,强烈建议使用 Low 和 High 函数,尤其是在循环中,因为它可以使代码独立于数组的当前范围(可能是从 0 到数组长度减 1,也可能是从 1 开始并达到数组长度,还可能是其他子界定义)。如果以后更改了数组索引的声明范围,使用 Low 和 High 的代码将自动生效,因为它们的值来自数组定义。相反,如果你编写一个硬编码数组范围的循环,那么当数组范围发生变化时,你就必须更新循环的代码。因此,使用 Low 和 High 不仅可以使代码更易于维护,而且更加可靠。

注解:顺便提一下,在静态数组中使用 Low 和 High 不会产生运行时开销。它们在编译时被解析为常量表达式,而不是实际的函数调用。这种表达式和函数调用的编译时解析也适用于许多其他系统函数。

​ 另一个相关函数是 Length,它返回数组的元素个数。在下面的代码中,我将这三个函数组合在一起,计算并显示当天的平均温度:

var
  I: Integer;
  Total: Integer;
  
begin
  Total := 0;
  for I := Low(DayTemp1) to High(DayTemp1) do
    Inc(Total, DayTemp1[I]);
  Show((Total / Length(DayTemp1)).ToString);
end;

这段代码也是ArraysTest示例的一部分。

5.1.3 多维静态数组

​ 数组可以有多个维度,表示矩阵或立方体,而不仅仅是一个列表。以下是两个示例定义:

type
  TAllMonthTemps = array[1..24, 1..31] of Integer;
  TAllYearTemps = array[1..24, 1..31, 1..12] of Integer;

​ 您可以这样访问一个元素:

var
  AllMonth1: TAllMonthTemps;
  AllYear1: TAllYearTemps;
  
begin
  AllMonth1[13, 30] := 55; // 小时,日期
  AllYear1[13, 30, 8] := 55; // 小时,日期,月份
end;

注解:静态数组随即占用了大量内存(上面的情况是在栈上),因此应避免这样做。AllYear1变量需要8,928个整数,每个整数占用4个字节,总共近35KB。在全局内存或栈中分配如此大的内存块(如演示代码中)确实是个错误。相比之下,动态数组使用堆内存,在内存分配和管理方面更具灵活性。

​ 由于这两种数组类型基于相同的核心类型,所以最好使用前面的数据类型来声明它们,如下所示:

type
  TMonthTemps = array[1..31] of TDayTemperatures;
  TYearTemps = array[1..12] of TMonthTemps;

​ 这个声明颠倒了上面介绍的索引顺序,但它还允许在变量之间进行整块的赋值。让我们看看如何给单个元素赋值:

Month1[30][14] := 44; // 天,小时
Month1[30, 13] := 55; // 天,小时
Year1[8, 30, 13] := 55; // 月份,天,小时

​ 使用中间类型的重要性在于,只有当数组引用了相同的类型名称(即完全相同的类型定义)时,它们才是类型兼容的,而不是它们的类型定义碰巧引用相同的实现。这种类型兼容性规则对Object Pascal中的所有类型都是一样的,只有一些特定的例外。

​ 例如,以下语句将一个月的温度复制到年的第三个月:

Year1[3] := Month1;

​ 相比之下,基于独立的数组定义的类似语句(它们不是类型兼容的):

AllYear1[3] := AllMonth1;

将导致错误:

Error: Incompatible types: 'array[1..31] of array[1..12] of Integer' and 'TAllMonthTemps'

​ 正如我所提到的,静态数组存在内存管理问题,特别是当你想将其作为参数传递或只分配大型数组的一部分时。此外,在数组变量的生命周期内,无法调整它们的大小。这就是为什么我们更倾向于使用动态数组的原因,即使动态数组需要一些额外的管理,比如需要分配内存。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MogaNet实战:使用 MogaNet实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度,DP多卡,EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

「Linux」软件安装

MySQL5.7在CentOS安装 安装 配置yum仓库 更新密钥:rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022安装MySQL yum库:rpm -Uvh http://repo.mysql.com//mysql57-community-release-el7-7.noarch.rpm使用yum安装MySQL:yum -y in…

接口测试 05 -- 接口加密处理

前言 实际工作当中,涉及到接口加密时,每一个公司加密方式都是不一样的。 1. 遇到接口加密的解决方法: ① 如果是一些常用的加密,可以通过 (第三方)工具或者代码去解决。 ② 如果是开发自己封装的加密方法,核心逻辑外人是无法知道的,最好的方式让开发去协助你。提供接口去…

ChinaXiv:中科院科技论文预发布平台

文章目录 Main彩蛋 Main 主页:https://chinaxiv.org/home.htm 彩蛋

python 笔记:shapely(形状篇)

主要是点(point)、线(linestring)、面(surface) 1 基本方法和属性 object.area 返回对象的面积(浮点数) object.bounds 返回一个(minx, miny, maxx, maxy)元…

发廊理发店微信小程序展示下单前端静态模板源码

模板描述:剪发小程序前端源码,一共五个页面,包括店铺、理发师、订单、我的等页面 注:该源码是前端静态模板源码,没有后台和API接口

【Linux进阶之路】网络——“?“(上)

文章目录 一、历史发展1. 独立形态2. 互联形态3. 局域网 二、网络协议1.OSI七层协议2.TCP/IP四(五)层模型 三、网络通信1.封装与解包2.数据的传输1.局域网2.广域网 总结尾序 本篇文章的目的是带大家初步认识网络,为后面的网络编程打下基础&am…

js基础(2)

对象 object也是js的一种数据类型 其静态特征可以用基本数据类型表示 动态行为可以用函数表示 语法: 增删改查 查:对象.属性 改: 对象.属性值 增:对象.新属性名新值 删:delete 对象.属性名 查的另一种写法: 对…

2024.2.3 作业

1、实现单向循环链表的头插头删尾插尾删 #include<stdio.h> #include<string.h> #include<stdlib.h> typedef int datatype; typedef struct node {//数据域int data;//指针域struct node *next; }*Linklist; Linklist create() {Linklist s(Linklist)mallo…

windows配置开机自启动软件或脚本

文章目录 windows配置开机自启动软件或脚本配置自启动目录开机运行的脚本调试开机自启动脚本配置守护进程(包装成自启动服务)使用任务计划程序FAQ 开机自动运行脚本示例 windows配置开机自启动软件或脚本 配置自启动目录 在Windows中添加开机自动运行的软件&#xff0c;可以按…

使用R语言建立回归模型并分割训练集和测试集

通过简单的回归实例&#xff0c;可以说明数据分割为训练集和测试集的必要性。以下先建立示例数据: set.seed(123) #设置随机种子 x <- rnorm(100, 2, 1) # 生成100个正态分布的随机数&#xff0c;均值为2&#xff0c;标准差为1 y exp(x) rnorm(5, 0, 2) # 生成一个新的变…

SQLyog安装配置(注册码)连接MySQL

下载资源 博主给你打包好了安装包&#xff0c;在网盘里&#xff0c;只有几Mb&#xff0c;防止你下载到钓鱼软件 快说谢谢博主&#xff08;然后心甘情愿的点个赞~&#x1f60a;&#xff09; SQLyog.zip 安装流程 ①下载好压缩包后并解压 ②打开文件夹&#xff0c;双击安装包 ③…

docker常用容器命令

首先说下容器&#xff1a; 它是指当docker运行镜像时&#xff0c;创建了一个隔离环境&#xff0c;称之为 容器。 这种方式优点&#xff1a;可以开启多个服务&#xff0c;服务之前是互相隔离的&#xff08;比如&#xff1a;在一台服务器上可以开启多个mysql&#xff0c;可以是…

【AI之路】使用RWKV-Runner启动大模型,彻底实现大模型自由

文章目录 前言一、RWKV-Runner是什么&#xff1f;RWKV-Runner是一个大语言模型的启动平台RWKV-Runner官方功能介绍 二、使用步骤1. 下载文件 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; ChatGPT的横空出世&#xff0c;打开了AI的大门&#xff…

【通讯录案例-保存开关状态 Objective-C语言】

一、接下来,我们要实现一个什么功能呢,在这个,我们的“通讯录”里边儿, 1.我们有两个开关,“记住密码”、“自动登录”、两个开关, 如果我们点击“记住密码”, 如果我们点击“记住密码”,然后呢,我把这个程序关了,我下一次再打开这个程序的时候,这个用户名和密码,…

Verilog刷题笔记30

题目&#xff1a; You are provided with a BCD one-digit adder named bcd_fadd that adds two BCD digits and carry-in, and produces a sum and carry-out. 解题&#xff1a; module top_module( input [399:0] a, b,input cin,output cout,output [399:0] sum );reg [99…

HTTP基本概念-HTTP 是什么?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) HTTP 是什么? HTTP 是超文本传输协议&#xff0c;也就是HyperText Transfer Protocol。 能否详细解释「超文本传输协议」? HTTP 的名字「超文本协议传输」&#xff0c;它可以拆成三个部分: 超文本传输…

ruoyi-nbcio中xxl-job的安装与使用

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a; http://122.227.135.243:9666 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbach…

【python】Fraction类详解及生成分数四则运算“试卷”

文章目录 一、前言实验所需的库终端指令Fraction类1. Fraction(numerator, denominator)&#xff1a;2. Fraction(numerator)3. Fraction()4. 分数作参数5. 负分数作参数6. 字符串作参数7. 小数作参数8. 科学计数法9. 浮点数作参数10. 浮点数精度问题11. Decimal对象作参数 二、…

力扣刷题之旅:高阶篇(三)—— 图算法的挑战

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 --点击进入刷题地址 引言 在算法世界的深处&#xff0c;图算法犹如一座高峰&#xff…