- Pascal 教程
- Pascal - 首页
- Pascal - 概述
- Pascal - 环境设置
- Pascal - 程序结构
- Pascal - 基本语法
- Pascal - 数据类型
- Pascal - 变量类型
- Pascal - 常量
- Pascal - 运算符
- Pascal - 决策制定
- Pascal - 循环
- Pascal - 函数
- Pascal - 过程
- Pascal - 变量作用域
- Pascal - 字符串
- Pascal - 布尔值
- Pascal - 数组
- Pascal - 指针
- Pascal - 记录
- Pascal - 变体
- Pascal - 集合
- Pascal - 文件处理
- Pascal - 内存
- Pascal - 单元
- Pascal - 日期和时间
- Pascal - 对象
- Pascal - 类
- Pascal 有用资源
- Pascal 快速指南
- Pascal - 有用资源
- Pascal - 讨论
Pascal 快速指南
Pascal - 概述
Pascal 是一种通用高级语言,最初由 Niklaus Wirth 于 20 世纪 70 年代初开发。它被开发用于将编程作为一种系统学科进行教学,并开发可靠且高效的程序。
Pascal 是一种基于 Algol 的语言,包含了许多 Algol 的结构。Algol 60 是 Pascal 的一个子集。Pascal 提供了几种数据类型和编程结构。Pascal 程序易于理解和维护。
Pascal 在教学和学术领域越来越受欢迎,原因有很多
- 易于学习。
- 结构化语言。
- 它生成透明、高效和可靠的程序。
- 它可以在各种计算机平台上编译。
Pascal 语言的特性
Pascal 具有以下特性:
- Pascal 是一种强类型语言。
- 它提供了广泛的错误检查。
- 它提供了几种数据类型,如数组、记录、文件和集合。
- 它提供各种编程结构。
- 它通过函数和过程支持结构化编程。
- 它支持面向对象编程。
关于 Pascal 的事实
Pascal 语言以法国数学家和计算机发展先驱 Blaise Pascal 的名字命名。
Niklaus Wirth 于 1970 年完成了原始 Pascal 编程语言的开发。
Pascal 基于 Algol 编程语言的块结构风格。
Pascal 被开发为一种适合将编程作为系统学科进行教学的语言,其实现既可靠又高效。
ISO 7185 Pascal 标准最初于 1983 年发布。
Pascal 是 Apple Lisa 和 Mac 早期开发中使用的一种主要高级语言。
1986 年,Apple Computer 发布了第一个 Object Pascal 实现,1993 年,Pascal 标准委员会发布了 Pascal 的面向对象扩展。
为什么要使用 Pascal?
Pascal 允许程序员定义复杂的结构化数据类型并构建动态和递归数据结构,例如列表、树和图。Pascal 提供了诸如记录、枚举、子范围、动态分配的变量以及关联指针和集合等功能。
Pascal 允许嵌套过程定义到任何深度。这确实为将编程作为基于基本概念的系统学科进行学习提供了极好的编程环境。
Pascal 最令人惊叹的实现包括:
- Skype
- Total Commander
- TeX
- Macromedia Captivate
- Apple Lisa
- 各种 PC 游戏
- 嵌入式系统
Pascal - 环境设置
有几种 Pascal 编译器和解释器可供一般使用。其中包括:
Turbo Pascal - 提供一个 IDE 和编译器,用于在 CP/M、CP/M-86、DOS、Windows 和 Macintosh 上运行 Pascal 程序。
Delphi - 提供编译器以运行 Object Pascal 并为 32 位和 64 位 Windows 操作系统以及 32 位 Mac OS X 和 iOS 生成本地代码。Embarcadero 计划构建对 Linux 和 Android 操作系统的支持。
Free Pascal - 它是一个免费的编译器,用于运行 Pascal 和 Object Pascal 程序。Free Pascal 编译器是一个 32 位和 64 位的 Turbo Pascal 和 Delphi 兼容的 Pascal 编译器,适用于 Linux、Windows、OS/2、FreeBSD、Mac OS X、DOS 和其他几个平台。
Turbo51 - 它是一个免费的 Pascal 编译器,用于 8051 系列微控制器,语法与 Turbo Pascal 7 相同。
Oxygene - 它是一个用于 .NET 和 Mono 平台的 Object Pascal 编译器。
GNU Pascal (GPC) - 它是一个 Pascal 编译器,由 GNU 编译器集合的前端组成。
在本教程中,我们将使用 Free Pascal。您可以从以下链接下载适合您操作系统的 Free Pascal:下载 Free Pascal
在 Linux 上安装 Free Pascal
Free Pascal 的 Linux 发行版有三种形式:
tar.gz 版本,也可作为单独的文件提供。
.rpm(Red Hat 软件包管理器)版本。
.deb(Debian)版本。
.rpm 版本的安装代码:
rpm -i fpc-X.Y.Z-N.ARCH.rpm
其中 X.Y.Z 是 .rpm 文件的版本号,ARCH 是受支持的体系结构之一(i386、x86_64 等)。
Debian 版本(如 Ubuntu)的安装代码:
dpkg -i fpc-XXX.deb
其中 XXX 是 .deb 文件的版本号。
详情请参阅:Free Pascal 安装指南
在 Mac 上安装 Free Pascal
如果您使用 Mac OS X,使用 Free Pascal 最简单的方法是从 Apple 的网站下载 Xcode 开发环境并按照简单的安装说明进行操作。设置好 Xcode 后,您就可以使用 Free Pascal 编译器了。
在 Windows 上安装 Free Pascal
对于 Windows,您将下载 Windows 安装程序 setup.exe。这是一个普通的安装程序。您需要执行以下步骤进行安装:
选择一个目录。
选择要安装的软件包部分。
可以选择将 .pp 或 .pas 扩展名与 Free Pascal IDE 关联起来。
详情请参阅:Free Pascal 安装指南
文本编辑器
这将用于键入您的程序。一些编辑器的示例包括 Windows 记事本、OS Edit 命令、Brief、Epsilon、EMACS 以及 vim 或 vi。
文本编辑器的名称和版本在不同的操作系统上可能会有所不同。例如,Notepad 将在 Windows 上使用,而 vim 或 vi 可以在 Windows 以及 Linux 或 UNIX 上使用。
使用编辑器创建的文件称为源文件,包含程序源代码。Pascal 程序的源文件通常以扩展名.pas命名。
在开始编程之前,请确保您已准备好一个文本编辑器,并且您有足够的经验来编写计算机程序,将其保存在文件中,编译它,最后执行它。
Pascal - 程序结构
在学习 Pascal 编程语言的基本构建块之前,让我们先看一下 Pascal 程序的最小结构,以便我们可以在接下来的章节中将其作为参考。
Pascal 程序结构
Pascal 程序主要由以下部分组成:
- 程序名称
- Uses 命令
- 类型声明
- 常量声明
- 变量声明
- 函数声明
- 过程声明
- 主程序块
- 每个块中的语句和表达式
- 注释
每个 Pascal 程序通常都有一个标题语句、一个声明部分和一个执行部分,并且严格按照此顺序排列。以下格式显示了 Pascal 程序的基本语法:
program {name of the program}
uses {comma delimited names of libraries you use}
const {global constant declaration block}
var {global variable declaration block}
function {function declarations, if any}
{ local variables }
begin
...
end;
procedure { procedure declarations, if any}
{ local variables }
begin
...
end;
begin { main program block starts}
...
end. { the end of main program block }
Pascal Hello World 示例
以下是一个简单的 Pascal 代码,它将打印“Hello, World!”:
program HelloWorld;
uses crt;
(* Here the main program block starts *)
begin
writeln('Hello, World!');
readkey;
end.
这将产生以下结果:
Hello, World!
让我们看一下上面程序的各个部分:
程序的第一行program HelloWorld;指示程序的名称。
程序的第二行uses crt;是一个预处理器命令,它告诉编译器在进行实际编译之前包含 crt 单元。
接下来在 begin 和 end 语句之间包含的行是主程序块。Pascal 中的每个块都包含在一个begin语句和一个end语句中。但是,指示主程序结束的 end 语句后面跟的是句点 (.) 而不是分号 (;)。
主程序块的begin语句是程序执行开始的地方。
(*...*)内的行将被编译器忽略,它被用来在程序中添加注释。
语句writeln('Hello, World!');使用 Pascal 中可用的 writeln 函数,该函数导致消息“Hello, World!”显示在屏幕上。
语句readkey;允许显示暂停,直到用户按下某个键。它是 crt 单元的一部分。单元类似于 Pascal 中的库。
最后一个语句end.结束您的程序。
编译和执行 Pascal 程序
打开一个文本编辑器并添加上述代码。
将文件保存为hello.pas
打开一个命令提示符并转到保存文件的目录。
在命令提示符下键入 fpc hello.pas 并按 Enter 键编译代码。
如果代码中没有错误,命令提示符将带您进入下一行,并将生成hello可执行文件和hello.o目标文件。
现在,在命令提示符下键入hello以执行程序。
您将能够看到“Hello World”打印在屏幕上,并且程序将等待您按下任何键。
$ fpc hello.pas Free Pascal Compiler version 2.6.0 [2011/12/23] for x86_64 Copyright (c) 1993-2011 by Florian Klaempfl and others Target OS: Linux for x86-64 Compiling hello.pas Linking hello 8 lines compiled, 0.1 sec $ ./hello Hello, World!
确保 free pascal 编译器fpc位于您的路径中,并且您在包含源文件 hello.pas 的目录中运行它。
Pascal - 基本语法
您已经看到了 Pascal 程序的基本结构,因此很容易理解 Pascal 编程语言的其他基本构建块。
变量
变量定义放在以var关键字开头的块中,后面跟着变量的定义,如下所示
var A_Variable, B_Variable ... : Variable_Type;
Pascal 变量声明在函数代码体之外,这意味着它们不在 **begin** 和 **end** 对内声明,而是在过程/函数定义之后以及 **begin** 关键字之前声明。对于全局变量,它们在程序头之后定义。
函数/过程
在 Pascal 中,**过程**是一组要执行的指令,没有返回值;而 **函数** 则是一个有返回值的过程。函数/过程的定义如下所示:
Function Func_Name(params...) : Return_Value; Procedure Proc_Name(params...);
注释
多行注释用花括号和星号括起来,如 (* ... *)。Pascal 允许用花括号 { ... } 括起来的单行注释。
(* This is a multi-line comments
and it will span multiple lines. *)
{ This is a single line comment in pascal }
大小写敏感性
Pascal 是一种不区分大小写的语言,这意味着您可以使用任何大小写编写变量、函数和过程。例如,变量 A_Variable、a_variable 和 A_VARIABLE 在 Pascal 中具有相同的含义。
Pascal 语句
Pascal 程序由语句组成。每个语句都指定程序的特定任务。这些任务可以是声明、赋值、读取数据、写入数据、进行逻辑决策、转移程序流程控制等。
例如:
readln (a, b, c); s := (a + b + c)/2.0; area := sqrt(s * (s - a)*(s-b)*(s-c)); writeln(area);
Pascal 中的保留字
Pascal 中的语句使用一些特定的 Pascal 词,这些词称为保留字。例如,单词 program、input、output、var、real、begin、readline、writeline 和 end 都是保留字。
以下是 Pascal 中可用的保留字列表。
| and | array | begin | case | const |
| div | do | downto | else | end |
| file | for | function | goto | if |
| in | label | mod | nil | not |
| of | or | packed | procedure | program |
| record | repeat | set | then | to |
| type | until | var | while | with |
Pascal 字符集和标识符
Pascal 字符集包含:
所有大写字母 (A-Z)
所有小写字母 (a-z)
所有数字 (0-9)
特殊符号 - + * / := , . ;. () [] = {} ` 空格
Pascal 程序中的实体,如变量和常量、类型、函数、过程和记录等,都有一个名称或标识符。标识符是由字母和数字组成的序列,以字母开头。标识符中不能使用特殊符号和空格。
Pascal - 数据类型
实体的数据类型表示与其关联的含义、约束、可能值、操作、函数和存储方式。
整数、实数、布尔和字符类型被称为标准数据类型。数据类型可以分为标量、指针和结构化数据类型。标量数据类型的示例包括整数、实数、布尔、字符、子范围和枚举。结构化数据类型由标量类型构成;例如,数组、记录、文件和集合。我们将在后面讨论指针数据类型。
Pascal 数据类型
Pascal 数据类型可以在下图中总结如下:
类型声明
类型声明用于声明标识符的数据类型。类型声明的语法如下:
type-identifier-1, type-identfier-2 = type-specifier;
例如,以下声明将变量 days 和 age 定义为整数类型,yes 和 true 定义为布尔类型,name 和 city 定义为字符串类型,fees 和 expenses 定义为实数类型。
type days, age = integer; yes, true = boolean; name, city = string; fees, expenses = real;
整数类型
下表提供了有关 Object Pascal 中使用的标准整数类型及其存储大小和值范围的详细信息:
| 类型 | 最小值 | 最大值 | 格式 |
|---|---|---|---|
| Integer | -2147483648 | 2147483647 | 有符号 32 位 |
| Cardinal | 0 | 4294967295 | 无符号 32 位 |
| Shortint | -128 | 127 | 有符号 8 位 |
| Smallint | -32768 | 32767 | 有符号 16 位 |
| Longint | -2147483648 | 2147483647 | 有符号 32 位 |
| Int64 | -2^63 | 2^63 - 1 | 有符号 64 位 |
| Byte | 0 | 255 | 无符号 8 位 |
| Word | 0 | 65535 | 无符号 16 位 |
| Longword | 0 | 4294967295 | 无符号 32 位 |
常量
使用常量使程序更具可读性,并有助于将特殊量集中放在程序开头的同一个位置。Pascal 允许声明 *数值、逻辑、字符串* 和 *字符* 常量。常量可以在程序的声明部分通过指定 **const** 声明来声明。
常量类型声明的语法如下:
const Identifier = contant_value;
以下是一些常量声明的示例:
VELOCITY_LIGHT = 3.0E=10; PIE = 3.141592; NAME = 'Stuart Little'; CHOICE = yes; OPERATOR = '+';
所有常量声明必须在变量声明之前给出。
枚举类型
枚举数据类型是用户定义的数据类型。它们允许在列表中指定值。在枚举数据类型上仅允许使用 *赋值* 运算符和 *关系* 运算符。枚举数据类型可以按如下方式声明:
type enum-identifier = (item1, item2, item3, ... )
以下是一些枚举类型声明的示例:
type SUMMER = (April, May, June, July, September); COLORS = (Red, Green, Blue, Yellow, Magenta, Cyan, Black, White); TRANSPORT = (Bus, Train, Airplane, Ship);
枚举类型域中列出项目的顺序定义了项目的顺序。例如,在枚举类型 SUMMER 中,April 在 May 之前,May 在 June 之前,依此类推。枚举类型标识符的域不能包含数字或字符常量。
子范围类型
子范围类型允许变量取值范围内的值。例如,如果选民的 *年龄* 应在 18 到 100 岁之间,则名为 age 的变量可以声明为:
var age: 18 ... 100;
我们将在下一节详细介绍变量声明。您还可以使用类型声明定义子范围类型。声明子范围类型的语法如下:
type subrange-identifier = lower-limit ... upper-limit;
以下是一些子范围类型声明的示例:
const P = 18; Q = 90; type Number = 1 ... 100; Value = P ... Q;
子范围类型可以从已定义的枚举类型的子集中创建,例如:
type months = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec); Summer = Apr ... Aug; Winter = Oct ... Dec;
Pascal - 变量类型
变量只不过是赋予存储区域的名称,我们的程序可以对其进行操作。Pascal 中的每个变量都有一个特定的类型,该类型决定了变量内存的大小和布局;可以存储在该内存中的值的范围;以及可以应用于变量的操作集。
变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。Pascal **不区分大小写**,因此这里大写和小写字母含义相同。根据上一章中解释的基本类型,将有以下基本变量类型:
Pascal 中的基本变量
| 序号 | 类型和描述 |
|---|---|
| 1 |
Character 通常是一个八位字节(一个字节)。这是一种整数类型。 |
| 2 | Integer 机器最自然的整数大小。 |
| 3 | Real 单精度浮点数。 |
| 4 | Boolean 指定 true 或 false 逻辑值。这同样也是整数类型。 |
| 5 | Enumerated 指定用户定义的列表。 |
| 6 | Subrange 表示变量,其值位于某个范围内。 |
| 7 | String 存储字符数组。 |
Pascal 编程语言还允许定义各种其他类型的变量,我们将在后续章节中介绍,例如指针、数组、记录、集合和文件等。在本节中,我们仅学习基本变量类型。
Pascal 中的变量声明
在 Pascal 程序中使用变量之前,必须先声明所有变量。所有变量声明后面都跟着 *var* 关键字。声明指定变量列表,后跟冒号 (:) 和类型。变量声明的语法如下:
var variable_list : type;
这里,type 必须是有效的 Pascal 数据类型,包括字符、整数、实数、布尔或任何用户定义的数据类型等,而 variable_list 可以包含一个或多个以逗号分隔的标识符名称。这里显示了一些有效的变量声明:
var age, weekdays : integer; taxrate, net_income: real; choice, isready: boolean; initials, grade: char; name, surname : string;
在前面的教程中,我们已经讨论过 Pascal 允许声明类型。类型可以用名称或标识符来识别。此类型可用于定义该类型的变量。例如,
type days, age = integer; yes, true = boolean; name, city = string; fees, expenses = real;
现在,可以将如此定义的类型用于变量声明:
var weekdays, holidays : days; choice: yes; student_name, emp_name : name; capital: city; cost: expenses;
请注意 *type* 声明和 *var* 声明之间的区别。类型声明指示类型的类别或种类,例如整数、实数等,而变量规范则指示变量可能取值的类型。您可以将 Pascal 中的 *type* 声明与 C 中的 *typedef* 进行比较。最重要的是,变量名指的是存储变量值的内存位置。类型声明并非如此。
Pascal 中的变量初始化
变量使用冒号和等号赋值,后跟常量表达式。赋值的一般形式如下:
variable_name := value;
默认情况下,Pascal 中的变量不会初始化为零。它们可能包含垃圾值。因此,在程序中初始化变量是一个更好的实践。可以在变量的声明中初始化(分配初始值)变量。初始化后跟 **var** 关键字,初始化的语法如下:
var variable_name : type = value;
以下是一些示例:
age: integer = 15; taxrate: real = 0.5; grade: char = 'A'; name: string = 'John Smith';
让我们看一个示例,它使用了迄今为止讨论过的各种类型的变量:
program Greetings;
const
message = ' Welcome to the world of Pascal ';
type
name = string;
var
firstname, surname: name;
begin
writeln('Please enter your first name: ');
readln(firstname);
writeln('Please enter your surname: ');
readln(surname);
writeln;
writeln(message, ' ', firstname, ' ', surname);
end.
当编译并执行上述代码时,它会产生以下结果:
Please enter your first name: John Please enter your surname: Smith Welcome to the world of Pascal John Smith
枚举变量
您已经了解了如何使用简单的变量类型,例如整数、实数和布尔。现在,让我们看看枚举类型的变量,它可以定义为:
var var1, var2, ... : enum-identifier;
声明枚举类型后,您可以声明该类型的变量。例如,
type months = (January, February, March, April, May, June, July, August, September, October, November, December); Var m: months; ... M := January;
以下示例说明了这个概念:
program exEnumeration;
type
beverage = (coffee, tea, milk, water, coke, limejuice);
var
drink:beverage;
begin
writeln('Which drink do you want?');
drink := limejuice;
writeln('You can drink ', drink);
end.
当编译并执行上述代码时,它会产生以下结果:
Which drink do you want? You can drink limejuice
子范围变量
子范围变量声明如下:
var subrange-name : lowerlim ... uperlim;
子范围变量的示例:
var marks: 1 ... 100; grade: 'A' ... 'E'; age: 1 ... 25;
以下程序说明了这个概念:
program exSubrange;
var
marks: 1 .. 100;
grade: 'A' .. 'E';
begin
writeln( 'Enter your marks(1 - 100): ');
readln(marks);
writeln( 'Enter your grade(A - E): ');
readln(grade);
writeln('Marks: ' , marks, ' Grade: ', grade);
end.
当编译并执行上述代码时,它会产生以下结果:
Enter your marks(1 - 100): 100 Enter your grade(A - E): A Marks: 100 Grade: A
Pascal - 常量
常量是在程序执行期间保持不变的实体。Pascal 仅允许声明以下类型的常量:
- 序数类型
- 集合类型
- 指针类型(但唯一允许的值是 Nil)。
- 实数类型
- Char
- String
声明常量
声明常量的语法如下:
const identifier = constant_value;
下表提供了一些有效常量声明的示例:
实数类型常量
| 序号 | 常量类型和示例 |
|---|---|
| 1 | 序数(整数)类型常量 valid_age = 21; |
| 2 | 集合类型常量 Vowels = set of (A,E,I,O,U); |
| 3 |
指针类型常量 P = NIL; |
| 4 |
e = 2.7182818; velocity_light = 3.0E+10; |
| 5 | 字符类型常量 Operator = '+'; |
| 6 | 字符串类型常量 president = 'Johnny Depp'; |
以下示例说明了这个概念:
program const_circle (input,output);
const
PI = 3.141592654;
var
r, d, c : real; {variable declaration: radius, dia, circumference}
begin
writeln('Enter the radius of the circle');
readln(r);
d := 2 * r;
c := PI * d;
writeln('The circumference of the circle is ',c:7:2);
end.
当编译并执行上述代码时,它会产生以下结果:
Enter the radius of the circle 23 The circumference of the circle is 144.51
观察程序输出语句中的格式。变量 c 将以总共 7 位数字和 2 位小数进行格式化。Pascal 允许对数值变量进行此类输出格式化。
Pascal - 运算符
运算符是告诉编译器执行特定数学或逻辑操作的符号。Pascal 允许以下类型的运算符:
- 算术运算符
- 关系运算符
- 布尔运算符
- 位运算符
- 集合运算符
- 字符串运算符
让我们逐一讨论算术运算符、关系运算符、布尔运算符和位运算符。集合运算符和字符串操作将在后面讨论。
算术运算符
下表显示了 Pascal 支持的所有算术运算符。假设变量A存储 10,变量B存储 20,则 -
| 运算符 | 描述 | 示例 |
|---|---|---|
| + | 将两个操作数相加 | A + B 将得到 30 |
| - | 从第一个操作数中减去第二个操作数 | A - B 将得到 -10 |
| * | 将两个操作数相乘 | A * B 将得到 200 |
| / | 将分子除以分母 | B / A 将得到 2 |
| % | 模运算符,整数除法后的余数 | B % A 将得到 0 |
关系运算符
下表显示了 Pascal 支持的所有关系运算符。假设变量A存储 10,变量B存储 20,则 -
| 运算符 | 描述 | 示例 |
|---|---|---|
| = | 检查两个操作数的值是否相等,如果相等,则条件为真。 | (A = B) 为假。 |
| <> | 检查两个操作数的值是否不相等,如果不相等,则条件为真。 | (A <> B) 为真。 |
| > | 检查左操作数的值是否大于右操作数的值,如果大于,则条件为真。 | (A > B) 为假。 |
| < | 检查左操作数的值是否小于右操作数的值,如果小于,则条件为真。 | (A < B) 为真。 |
| >= | 检查左操作数的值是否大于或等于右操作数的值,如果大于或等于,则条件为真。 | (A >= B) 为假。 |
| <= | 检查左操作数的值是否小于或等于右操作数的值,如果小于或等于,则条件为真。 | (A <= B) 为真。 |
布尔运算符
下表显示了 Pascal 语言支持的所有布尔运算符。所有这些运算符都作用于布尔操作数并产生布尔结果。假设变量A存储 true,变量B存储 false,则 -
| 运算符 | 描述 | 示例 |
|---|---|---|
| and | 称为布尔 AND 运算符。如果两个操作数都为真,则条件为真。 | (A and B) 为假。 |
| 以及 | 它类似于 AND 运算符,但是它保证了编译器评估逻辑表达式的顺序。从左到右,仅在必要时才评估右侧操作数。 | (A and then B) 为假。 |
| or | 称为布尔 OR 运算符。如果两个操作数中的任何一个为真,则条件为真。 | (A or B) 为真。 |
| 或者 | 它类似于布尔 OR,但是它保证了编译器评估逻辑表达式的顺序。从左到右,仅在必要时才评估右侧操作数。 | (A or else B) 为真。 |
| not | 称为布尔 NOT 运算符。用于反转其操作数的逻辑状态。如果条件为真,则逻辑 NOT 运算符将使其变为假。 | not (A and B) 为真。 |
位运算符
位运算符作用于位并执行逐位运算。所有这些运算符都作用于整数操作数并产生整数结果。位与 (&)、位或 (|) 和位非 (~) 的真值表如下所示 -
| p | q | p & q | p | q | ~p | ~q |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 | 0 |
| 1 | 1 | 1 | 1 | 0 | 0 |
| 1 | 0 | 0 | 1 | 0 | 1 |
假设 A = 60;B = 13;现在以二进制格式,它们将如下所示 -
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A^B = 0011 0001
~A = 1100 0011
Pascal 支持的位运算符列在下表中。假设变量 A 存储 60,变量 B 存储 13,则
| 运算符 | 描述 | 示例 |
|---|---|---|
| & | 二进制 AND 运算符将位复制到结果中,如果它存在于两个操作数中。 | (A & B) 将得到 12,即 0000 1100 |
| | | 二进制 OR 运算符将复制存在于任何一个操作数中的位。 | (A | B) 将得到 61,即 0011 1101 |
| ! | 二进制 OR 运算符将复制存在于任何一个操作数中的位。它与 | 运算符相同。 | (A ! B) 将得到 61,即 0011 1101 |
| ~ | 二进制一补码运算符是一元的,其作用是“翻转”位。 | (~A ) 将得到 -61,由于带符号二进制数,它以 2 的补码形式表示为 1100 0011。 |
| << | 二进制左移运算符。左操作数的值向左移动由右操作数指定的位数。 | A << 2 将得到 240,即 1111 0000 |
| >> | 二进制右移运算符。左操作数的值向右移动由右操作数指定的位数。 | A >> 2 将得到 15,即 0000 1111 |
请注意,Pascal 的不同实现方式在位运算符方面有所不同。但是,我们在此使用的编译器 Free Pascal 支持以下位运算符 -
| 运算符 | 操作 |
|---|---|
| not | 位非 |
| and | 位与 |
| or | 位或 |
| 异或 | 位异或 |
| 左移 | 位左移 |
| 右移 | 位右移 |
| << | 位左移 |
| >> | 位右移 |
Pascal 中运算符的优先级
运算符优先级决定了表达式中项的组合方式。这会影响表达式的计算方式。某些运算符的优先级高于其他运算符;例如,乘法运算符的优先级高于加法运算符。
例如 x = 7 + 3 * 2;此处,x 被赋值为 13,而不是 20,因为运算符 * 的优先级高于 +,所以它首先与 3*2 相乘,然后加到 7 中。
在此,优先级最高的运算符出现在表的最上面,优先级最低的出现在最下面。在表达式中,优先级较高的运算符将首先被计算。
| 运算符 | 优先级 |
|---|---|
| ~, not, | 最高 |
| *, /, div, mod, and, & | |
| |, !, +, -, or, | |
| =, <>, <, <=, >, >=, in | |
| or else, and then | 最低 |
Pascal - 决策制定
决策结构要求程序员指定一个或多个条件,由程序进行评估或测试,以及在确定条件为真时要执行的语句或语句,以及可选地在确定条件为假时要执行的其他语句。
以下是大多数编程语言中典型的决策结构的通用形式 -
Pascal 编程语言提供了以下类型的决策语句。点击以下链接查看其详细信息。
| 序号 | 语句和描述 |
|---|---|
| 1 |
if - then 语句
if - then 语句由一个布尔表达式后跟一个或多个语句组成。 |
| 2 |
If-then-else 语句
if - then 语句后面可以跟一个可选的else 语句,当布尔表达式为假时执行该语句。 |
| 3 |
嵌套 if 语句
您可以在另一个if或else if语句中使用一个if或else if语句。 |
| 4 |
case 语句
case语句允许将变量与其值的列表进行相等性测试。 |
| 5 |
case - else 语句
它类似于if-then-else语句。此处,else项位于case 语句之后。 |
| 6 |
嵌套 case 语句
您可以在另一个case语句中使用一个case语句。 |
Pascal - 循环
可能存在这样的情况,您需要多次执行一段代码。通常,语句按顺序执行:函数中的第一个语句首先执行,然后是第二个语句,依此类推。
编程语言提供了各种控制结构,允许更复杂的执行路径。
循环语句允许我们多次执行一个语句或一组语句,以下是大多数编程语言中循环语句的通用形式 -
Pascal 编程语言提供了以下类型的循环结构来处理循环需求。点击以下链接查看其详细信息。
| 序号 | 循环类型和描述 |
|---|---|
| 1 |
while-do 循环
在给定条件为真的情况下重复执行一个语句或一组语句。它在执行循环体之前测试条件。 |
| 2 |
for-do 循环
多次执行一系列语句,并缩写管理循环变量的代码。 |
| 3 |
repeat-until 循环
类似于 while 语句,但它在循环体末尾测试条件。 |
| 4 |
嵌套循环
您可以在任何其他 while、for 或 repeat until 循环中使用一个或多个循环。 |
循环控制语句
循环控制语句更改执行的正常顺序。当执行离开作用域时,在该作用域中创建的所有自动对象都将被销毁。
Pascal 支持以下控制语句。点击以下链接查看其详细信息。
| 序号 | 控制语句和描述 |
|---|---|
| 1 |
break 语句
终止loop或case语句,并将执行转移到紧随 loop 或 case 语句之后的语句。 |
| 2 |
continue 语句
导致循环跳过其主体剩余部分,并在立即重新迭代之前立即重新测试其条件。 |
| 3 | goto 语句
将控制权转移到带标签的语句。虽然不建议在程序中使用 goto 语句。 |
Pascal - 函数
子程序
子程序是一个执行特定任务的程序单元/模块。这些子程序组合在一起形成更大的程序。这基本上称为“模块化设计”。子程序可以由子程序/程序调用,该子程序/程序称为调用程序。
Pascal 提供两种子程序 -
函数 - 这些子程序返回单个值。
过程 - 这些子程序不直接返回值。
函数
函数是一组共同执行任务的语句。每个 Pascal 程序至少有一个函数,即程序本身,并且大多数最简单的程序都可以定义其他函数。
函数**声明**告诉编译器函数的名称、返回类型和参数。函数**定义**提供了函数的实际主体。
Pascal 标准库提供了许多内置函数,您的程序可以调用这些函数。例如,函数**AppendStr()**连接两个字符串,函数**New()**为变量动态分配内存,还有许多其他函数。
定义函数
在 Pascal 中,使用 function 关键字定义**函数**。函数定义的一般形式如下:
function name(argument(s): type1; argument(s): type2; ...): function_type; local declarations; begin ... < statements > ... name:= expression; end;
Pascal 中的函数定义由函数**头部**、局部**声明**和函数**体**组成。函数头部包含关键字 function 和赋予函数的**名称**。以下是函数的所有部分:
**参数** - 参数建立了调用程序和函数标识符之间的联系,也称为形式参数。参数就像一个占位符。当调用函数时,您将值传递给参数。此值称为实际参数或参数。参数列表指的是函数的参数类型、顺序和数量。使用此类形式参数是可选的。这些参数可以具有标准数据类型、用户定义的数据类型或子范围数据类型。
出现在函数语句中的形式参数列表可以是简单变量或带下标的变量、数组或结构化变量,或子程序。
**返回类型** - 所有函数都必须返回一个值,因此所有函数都必须分配一个类型。**函数类型**是函数返回值的数据类型。它可以是标准的、用户定义的标量或子范围类型,但不能是结构化类型。
**局部声明** - 局部声明指的是标签、常量、变量、函数和过程的声明,这些声明仅适用于函数体。
**函数体** - 函数体包含定义函数功能的一组语句。它应该始终用保留字 begin 和 end 括起来。它是函数中执行所有计算的部分。函数体中必须有一个类型为 - **name := expression;** 的赋值语句,该语句将值赋给函数名。此值在执行函数时返回。主体中的最后一个语句必须是 end 语句。
以下是一个示例,展示了如何在 pascal 中定义函数:
(* function returning the max between two numbers *)
function max(num1, num2: integer): integer;
var
(* local variable declaration *)
result: integer;
begin
if (num1 > num2) then
result := num1
else
result := num2;
max := result;
end;
函数声明
函数**声明**告诉编译器函数名称以及如何调用函数。函数的实际主体可以单独定义。
函数声明包含以下部分:
function name(argument(s): type1; argument(s): type2; ...): function_type;
对于上面定义的函数 max(),以下是函数声明:
function max(num1, num2: integer): integer;
当您在一个源文件中定义函数并在另一个文件中调用该函数时,需要进行函数声明。在这种情况下,您应该在调用函数的文件顶部声明该函数。
调用函数
在创建函数时,您会定义函数需要执行的操作。要使用函数,您必须调用该函数以执行定义的任务。当程序调用函数时,程序控制权将转移到被调用函数。被调用函数执行定义的任务,当执行其 return 语句或到达其最后一个 end 语句时,它将程序控制权返回给主程序。
要调用函数,您只需将所需的参数与函数名称一起传递,如果函数返回值,则可以存储返回值。以下是一个简单的示例,展示了用法:
program exFunction;
var
a, b, ret : integer;
(*function definition *)
function max(num1, num2: integer): integer;
var
(* local variable declaration *)
result: integer;
begin
if (num1 > num2) then
result := num1
else
result := num2;
max := result;
end;
begin
a := 100;
b := 200;
(* calling a function to get max value *)
ret := max(a, b);
writeln( 'Max value is : ', ret );
end.
当编译并执行上述代码时,它会产生以下结果:
Max value is : 200
Pascal - 过程
**过程**是子程序,它们不返回单个值,而是允许获取一组结果。
定义过程
在 Pascal 中,使用**procedure**关键字定义过程。过程定义的一般形式如下:
procedure name(argument(s): type1, argument(s): type 2, ... ); < local declarations > begin < procedure body > end;
Pascal 中的过程定义由**头部**、局部**声明**和过程**体**组成。过程头部包含关键字**procedure**和赋予过程的名称。以下是过程的所有部分:
**参数** - 参数建立了调用程序和过程标识符之间的联系,也称为形式参数。过程参数的规则与函数相同。
**局部声明** - 局部声明指的是标签、常量、变量、函数和过程的声明,这些声明仅适用于过程体。
**过程体** - 过程体包含定义过程功能的一组语句。它应该始终用保留字 begin 和 end 括起来。它是过程执行所有计算的部分。
以下是名为findMin()的过程的源代码。此过程接受 4 个参数 x、y、z 和 m,并将前三个变量中的最小值存储在名为 m 的变量中。变量 m 通过**引用**传递(稍后我们将讨论通过引用传递参数):
procedure findMin(x, y, z: integer; var m: integer);
(* Finds the minimum of the 3 values *)
begin
if x < y then
m := x
else
m := y;
if z <m then
m := z;
end; { end of procedure findMin }
过程声明
过程**声明**告诉编译器过程名称以及如何调用过程。过程的实际主体可以单独定义。
过程声明具有以下语法:
procedure name(argument(s): type1, argument(s): type 2, ... );
请注意,**过程的名称与任何类型都不相关**。对于上面定义的过程findMin(),以下是声明:
procedure findMin(x, y, z: integer; var m: integer);
调用过程
在创建过程时,您会定义过程需要执行的操作。要使用该过程,您必须调用该过程以执行定义的任务。当程序调用过程时,程序控制权将转移到被调用过程。被调用过程执行定义的任务,当到达其最后一个 end 语句时,它将控制权返回给调用程序。
要调用过程,您只需将所需的参数与过程名称一起传递,如下所示:
program exProcedure;
var
a, b, c, min: integer;
procedure findMin(x, y, z: integer; var m: integer);
(* Finds the minimum of the 3 values *)
begin
if x < y then
m:= x
else
m:= y;
if z < m then
m:= z;
end; { end of procedure findMin }
begin
writeln(' Enter three numbers: ');
readln( a, b, c);
findMin(a, b, c, min); (* Procedure call *)
writeln(' Minimum: ', min);
end.
当编译并执行上述代码时,它会产生以下结果:
Enter three numbers: 89 45 67 Minimum: 45
递归子程序
我们已经看到,程序或子程序可以调用另一个子程序。当子程序调用自身时,称为递归调用,该过程称为递归。
为了说明这个概念,让我们计算一个数字的阶乘。数字 n 的阶乘定义为:
n! = n*(n-1)!
= n*(n-1)*(n-2)!
...
= n*(n-1)*(n-2)*(n-3)... 1
以下程序通过递归调用自身来计算给定数字的阶乘。
program exRecursion;
var
num, f: integer;
function fact(x: integer): integer; (* calculates factorial of x - x! *)
begin
if x=0 then
fact := 1
else
fact := x * fact(x-1); (* recursive call *)
end; { end of function fact}
begin
writeln(' Enter a number: ');
readln(num);
f := fact(num);
writeln(' Factorial ', num, ' is: ' , f);
end.
当编译并执行上述代码时,它会产生以下结果:
Enter a number: 5 Factorial 5 is: 120
以下另一个示例,使用**递归**函数为给定数字生成**斐波那契数列**:
program recursiveFibonacci;
var
i: integer;
function fibonacci(n: integer): integer;
begin
if n=1 then
fibonacci := 0
else if n=2 then
fibonacci := 1
else
fibonacci := fibonacci(n-1) + fibonacci(n-2);
end;
begin
for i:= 1 to 10 do
write(fibonacci (i), ' ');
end.
当编译并执行上述代码时,它会产生以下结果:
0 1 1 2 3 5 8 13 21 34
子程序的参数
如果子程序(**函数或过程**)要使用参数,则必须声明接受参数值的变量。这些变量称为子程序的**形式参数**。
形式参数在子程序内部的行为类似于其他局部变量,并在进入子程序时创建,并在退出时销毁。
在调用子程序时,有两种方法可以将参数传递给子程序:
| 序号 | 调用类型和描述 |
|---|---|
| 1 |
按值调用
此方法将参数的实际值复制到子程序的形式参数中。在这种情况下,对子程序内部参数所做的更改不会影响参数。 |
| 2 |
按引用调用
此方法将参数的地址复制到形式参数中。在子程序内部,该地址用于访问调用中使用的实际参数。这意味着对参数所做的更改会影响参数。 |
默认情况下,Pascal 使用**按值调用**来传递参数。通常,这意味着子程序中的代码无法更改用于调用子程序的参数。我们在“Pascal - 函数”一章中使用的示例程序使用**按值调用**来调用名为 max() 的函数。
而此处提供的示例程序(exProcedure)使用**按引用调用**来调用过程 findMin()。
Pascal - 变量作用域
任何编程中的作用域都是程序的一个区域,其中定义的变量可以存在,并且超出该范围变量无法访问。在 Pascal 编程语言中,可以在三个地方声明变量:
在子程序或块内,称为局部变量
在所有子程序之外,称为全局变量
在子程序参数的定义中,称为形式参数
让我们解释一下什么是**局部**变量和**全局**变量以及形式参数。
局部变量
在子程序或块内声明的变量称为局部变量。它们只能被子程序或代码块内的语句使用。局部变量对子程序外部的子程序是未知的。以下是用局部变量的示例。此处,所有变量a、b和c都对名为exLocal的程序是局部的。
program exLocal;
var
a, b, c: integer;
begin
(* actual initialization *)
a := 10;
b := 20;
c := a + b;
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
end.
当编译并执行上述代码时,它会产生以下结果:
value of a = 10 b = 20 c = 30
现在,让我们进一步扩展程序,让我们创建一个名为 display 的过程,该过程将拥有自己的变量集a、b和c,并显示它们的值,直接来自程序exLocal。
program exLocal;
var
a, b, c: integer;
procedure display;
var
a, b, c: integer;
begin
(* local variables *)
a := 10;
b := 20;
c := a + b;
writeln('Winthin the procedure display');
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
end;
begin
a:= 100;
b:= 200;
c:= a + b;
writeln('Winthin the program exlocal');
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
display();
end.
当编译并执行上述代码时,它会产生以下结果:
Within the program exlocal value of a = 100 b = 200 c = 300 Within the procedure display value of a = 10 b = 20 c = 30
全局变量
全局变量在函数外部定义,通常在程序顶部。全局变量将在程序的整个生命周期内保持其值,并且可以在为程序定义的任何函数内部访问它们。
任何函数都可以访问**全局**变量。也就是说,全局变量在声明后可以在整个程序中使用。以下是用**全局**变量和**局部**变量的示例:
program exGlobal;
var
a, b, c: integer;
procedure display;
var
x, y, z: integer;
begin
(* local variables *)
x := 10;
y := 20;
z := x + y;
(*global variables *)
a := 30;
b:= 40;
c:= a + b;
writeln('Winthin the procedure display');
writeln(' Displaying the global variables a, b, and c');
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
writeln('Displaying the local variables x, y, and z');
writeln('value of x = ', x , ' y = ', y, ' and z = ', z);
end;
begin
a:= 100;
b:= 200;
c:= 300;
writeln('Winthin the program exlocal');
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
display();
end.
当编译并执行上述代码时,它会产生以下结果:
Within the program exlocal value of a = 100 b = 200 c = 300 Within the procedure display Displaying the global variables a, b, and c value of a = 30 b = 40 c = 70 Displaying the local variables x, y, and z value of x = 10 y = 20 z = 30
请注意,过程 display 可以访问变量 a、b 和 c,这些变量相对于 display 以及它自己的局部变量是全局变量。程序可以为局部变量和全局变量使用相同的名称,但函数内部局部变量的值将优先。
让我们稍微修改一下前面的示例,现在过程 display 的局部变量与a、b、c具有相同的名称:
program exGlobal;
var
a, b, c: integer;
procedure display;
var
a, b, c: integer;
begin
(* local variables *)
a := 10;
b := 20;
c := a + b;
writeln('Winthin the procedure display');
writeln(' Displaying the global variables a, b, and c');
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
writeln('Displaying the local variables a, b, and c');
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
end;
begin
a:= 100;
b:= 200;
c:= 300;
writeln('Winthin the program exlocal');
writeln('value of a = ', a , ' b = ', b, ' and c = ', c);
display();
end.
当编译并执行上述代码时,它会产生以下结果:
Within the program exlocal value of a = 100 b = 200 c = 300 Within the procedure display Displaying the global variables a, b, and c value of a = 10 b = 20 c = 30 Displaying the local variables a, b, and c value of a = 10 b = 20 c = 30
Pascal - 字符串
Pascal 中的字符串实际上是字符序列,带有一个可选的大小说明。字符可以是数字、字母、空格、特殊字符或所有字符的组合。扩展 Pascal 根据系统和实现提供了多种类型的字符串对象。我们将讨论程序中使用的更常见的字符串类型。
您可以通过多种方式定义字符串:
**字符数组** - 这是一串字符,它是零个或多个字节大小的字符的序列,用单引号括起来。
**字符串变量** - 如 Turbo Pascal 中定义的 String 类型的变量。
**短字符串** - 带有大小说明的 String 类型的变量。
**以 null 结尾的字符串** - pchar类型的变量。
**AnsiStrings** - Ansistrings 是没有长度限制的字符串。
Pascal 仅提供一个字符串运算符,即字符串连接运算符 (+)。
示例
以下程序打印前四种字符串。我们将在下一个示例中使用 AnsiStrings。
program exString;
var
greetings: string;
name: packed array [1..10] of char;
organisation: string[10];
message: pchar;
begin
greetings := 'Hello ';
message := 'Good Day!';
writeln('Please Enter your Name');
readln(name);
writeln('Please Enter the name of your Organisation');
readln(organisation);
writeln(greetings, name, ' from ', organisation);
writeln(message);
end.
当编译并执行上述代码时,它会产生以下结果:
Please Enter your Name John Smith Please Enter the name of your Organisation Infotech Hello John Smith from Infotech
以下示例使用了更多函数,让我们看看:
program exString;
uses sysutils;
var
str1, str2, str3 : ansistring;
str4: string;
len: integer;
begin
str1 := 'Hello ';
str2 := 'There!';
(* copy str1 into str3 *)
str3 := str1;
writeln('appendstr( str3, str1) : ', str3 );
(* concatenates str1 and str2 *)
appendstr( str1, str2);
writeln( 'appendstr( str1, str2) ' , str1 );
str4 := str1 + str2;
writeln('Now str4 is: ', str4);
(* total lenghth of str4 after concatenation *)
len := byte(str4[0]);
writeln('Length of the final string str4: ', len);
end.
当编译并执行上述代码时,它会产生以下结果:
appendstr( str3, str1) : Hello appendstr( str1, str2) : Hello There! Now str4 is: Hello There! There! Length of the final string str4: 18
Pascal 字符串函数和过程
Pascal 支持广泛的用于操作字符串的函数和过程。这些子程序在实现方面有所不同。在这里,我们列出了 Free Pascal 提供的各种字符串操作子程序:
| 序号 | 函数和用途 |
|---|---|
| 1 |
function AnsiCompareStr(const S1: string; const S2: string):Integer; 比较两个字符串 |
| 2 |
function AnsiCompareText(const S1: string; const S2: string):Integer; 比较两个字符串,不区分大小写 |
| 3 |
function AnsiExtractQuotedStr(var Src: PChar; Quote: Char):string; 去除字符串中的引号 |
| 4 |
function AnsiLastChar(const S: string):PChar; 获取字符串的最后一个字符 |
| 5 |
function AnsiLowerCase(const s: string):string; 将字符串转换为全小写 |
| 6 |
function AnsiQuotedStr(const S: string; Quote: Char):string; 为字符串添加引号 |
| 7 |
function AnsiStrComp(S1: PChar;S2: PChar):Integer; 比较字符串,区分大小写 |
| 8 |
function AnsiStrIComp(S1: PChar; S2: PChar):Integer; 比较字符串,不区分大小写 |
| 9 |
function AnsiStrLComp(S1: PChar; S2: PChar; MaxLen: Cardinal):Integer; 比较字符串前 L 个字符,区分大小写 |
| 10 |
function AnsiStrLIComp(S1: PChar; S2: PChar; MaxLen: Cardinal):Integer; 比较字符串前 L 个字符,不区分大小写 |
| 11 |
function AnsiStrLastChar(Str: PChar):PChar; 获取字符串的最后一个字符 |
| 12 |
function AnsiStrLower(Str: PChar):PChar; 将字符串转换为全小写 |
| 13 |
function AnsiStrUpper(Str: PChar):PChar; 将字符串转换为全大写 |
| 14 |
function AnsiUpperCase(const s: string):string; 将字符串转换为全大写 |
| 15 |
procedure AppendStr(var Dest: string; const S: string); 连接两个字符串 |
| 16 |
procedure AssignStr(var P: PString; const S: string); 在堆上分配字符串的值 |
| 17 |
function CompareStr(const S1: string; const S2: string):Integer; overload; 比较两个字符串,区分大小写 |
| 18 |
function CompareText(const S1: string; const S2: string):Integer; 比较两个字符串,不区分大小写 |
| 19 |
procedure DisposeStr(S: PString); overload;
从堆中释放字符串 |
| 20 |
procedure DisposeStr(S: PShortString); overload; 从堆中释放字符串 |
| 21 |
function IsValidIdent( const Ident: string):Boolean; 判断字符串是否为有效的 Pascal 标识符 |
| 22 |
function LastDelimiter(const Delimiters: string; const S: string):Integer; 查找字符串中最后一个出现的字符 |
| 23 |
function LeftStr(const S: string; Count: Integer):string; 获取字符串的前 N 个字符 |
| 24 |
function LoadStr(Ident: Integer):string; 从资源中加载字符串 |
| 25 |
function LowerCase(const s: string ):string; overload; 将字符串转换为全小写 |
| 26 |
function LowerCase(const V: variant ):string; overload; 将字符串转换为全小写 |
| 27 |
function NewStr(const S: string):PString; overload; 在堆上分配新的字符串 |
| 28 |
function RightStr(const S: string; Count: Integer):string; 获取字符串的后 N 个字符 |
| 29 |
function StrAlloc(Size: Cardinal):PChar; 为字符串分配内存 |
| 30 |
function StrBufSize(Str: PChar):SizeUInt; 为字符串预留内存 |
| 31 |
procedure StrDispose(Str: PChar); 从堆中释放字符串 |
| 32 |
function StrPas(Str: PChar):string; 将 PChar 转换为 Pascal 字符串 |
| 33 |
function StrPCopy(Dest: PChar; Source: string):PChar; 复制 Pascal 字符串 |
| 34 |
function StrPLCopy(Dest: PChar; Source: string; MaxLen: SizeUInt):PChar; 复制 Pascal 字符串的前 N 个字节 |
| 35 |
function UpperCase(const s: string):string; 将字符串转换为全大写 |
Pascal - 布尔值
Pascal 提供了布尔数据类型 Boolean,使程序员能够定义、存储和操作逻辑实体,例如常量、变量、函数和表达式等。
布尔值本质上是整数类型。布尔类型变量有两个预定义的可能值:**True** 和 **False**。解析为布尔值的表达式也可以赋值给布尔类型。
Free Pascal 还支持 **ByteBool**、**WordBool** 和 **LongBool** 类型。这些类型分别为 Byte、Word 或 Longint 类型。
值 False 等效于 0(零),任何非零值在转换为布尔值时都被视为 True。如果将 True 的布尔值赋值给 LongBool 类型的变量,则将其转换为 -1。
需要注意的是,逻辑运算符 **and**、**or** 和 **not** 是为布尔数据类型定义的。
布尔数据类型的声明
使用 var 关键字声明布尔类型变量。
var boolean-identifier: boolean;
例如,
var choice: boolean;
示例
program exBoolean;
var
exit: boolean;
choice: char;
begin
writeln('Do you want to continue? ');
writeln('Enter Y/y for yes, and N/n for no');
readln(choice);
if(choice = 'n') then
exit := true
else
exit := false;
if (exit) then
writeln(' Good Bye!')
else
writeln('Please Continue');
readln;
end.
当编译并执行上述代码时,它会产生以下结果:
Do you want to continue? Enter Y/y for yes, and N/n for no N Good Bye! Y Please Continue
Pascal - 数组
Pascal 编程语言提供了一种称为数组的数据结构,它可以存储相同类型元素的固定大小的顺序集合。数组用于存储数据集合,但通常将数组视为相同类型变量的集合更有用。
与其声明单独的变量,例如 number1、number2、... 和 number100,不如声明一个数组变量,例如 numbers,并使用 numbers[1]、numbers[2] 和 ...、numbers[100] 来表示各个变量。数组中的特定元素通过索引访问。
所有数组都由连续的内存位置组成。最低地址对应于第一个元素,最高地址对应于最后一个元素。
请注意,如果您希望从索引 0 开始的 C 样式数组,只需将索引从 0 开始,而不是从 1 开始。
数组的声明
要在 Pascal 中声明数组,程序员可以声明类型,然后创建该数组的变量,或者直接声明数组变量。
一维数组类型声明的一般形式为:
type array-identifier = array[index-type] of element-type;
其中,
**array-identifier** - 表示数组类型的名称。
**index-type** - 指定数组的下标;它可以是除实数之外的任何标量数据类型
**element-type** - 指定要存储的值的类型
例如,
type vector = array [ 1..25] of real; var velocity: vector;
现在,velocity 是 vector 类型的变量数组,足以容纳多达 25 个实数。
要从索引 0 开始数组,声明将为:
type vector = array [ 0..24] of real; var velocity: vector;
数组下标的类型
在 Pascal 中,数组下标可以是任何标量类型,如整数、布尔值、枚举或子范围,但实数除外。数组下标也可以具有负值。
例如,
type temperature = array [-10 .. 50] of real; var day_temp, night_temp: temperature;
让我们举另一个下标为字符类型的例子:
type ch_array = array[char] of 1..26; var alphabet: ch_array;
下标可以是枚举类型:
type color = ( red, black, blue, silver, beige); car_color = array of [color] of boolean; var car_body: car_color;
数组的初始化
在 Pascal 中,数组通过赋值进行初始化,可以通过指定特定的下标或使用 for-do 循环来初始化。
例如:
type ch_array = array[char] of 1..26; var alphabet: ch_array; c: char; begin ... for c:= 'A' to 'Z' do alphabet[c] := ord[m]; (* the ord() function returns the ordinal values *)
访问数组元素
通过对数组名称进行索引来访问元素。这是通过在数组名称后方方括号内放置元素的索引来完成的。例如:
a: integer; a: = alphabet['A'];
以上语句将从名为 alphabet 的数组中获取第一个元素,并将该值赋给变量 a。
以下是一个示例,它将使用上述所有三个概念,即数组的声明、赋值和访问:
program exArrays;
var
n: array [1..10] of integer; (* n is an array of 10 integers *)
i, j: integer;
begin
(* initialize elements of array n to 0 *)
for i := 1 to 10 do
n[ i ] := i + 100; (* set element at location i to i + 100 *)
(* output each array element's value *)
for j:= 1 to 10 do
writeln('Element[', j, '] = ', n[j] );
end.
当编译并执行上述代码时,它会产生以下结果:
Element[1] = 101 Element[2] = 102 Element[3] = 103 Element[4] = 104 Element[5] = 105 Element[6] = 106 Element[7] = 107 Element[8] = 108 Element[9] = 109 Element[10] = 110
Pascal 数组详解
数组对 Pascal 来说很重要,需要更多细节。以下是一些与数组相关的重要的概念,Pascal 程序员应该清楚:
| 序号 | 概念和描述 |
|---|---|
| 1 |
多维数组
Pascal 支持多维数组。多维数组最简单的形式是二维数组。 |
| 2 |
动态数组
在这种类型的数组中,初始长度为零。数组的实际长度必须使用标准 **SetLength** 函数设置。 |
| 3 |
压缩数组
这些数组是按位压缩的,即每个字符或真值都存储在连续的字节中,而不是使用一个存储单元,通常是一个字(4 个字节或更多)。 |
| 4 |
将数组传递给子程序
您可以通过指定数组的名称而不带索引来将数组的指针传递给子程序。 |
Pascal - 指针
Pascal 中的指针易于学习且趣味十足。一些 Pascal 编程任务使用指针更容易执行,而其他任务(例如动态内存分配)则无法在不使用指针的情况下执行。因此,学习指针成为一名完美的 Pascal 程序员是必要的。让我们以简单易懂的步骤开始学习它们。
如您所知,每个变量都是一个内存位置,并且每个内存位置都有其定义的地址,可以使用指针变量的名称来访问该地址,该指针变量表示内存中的地址。
什么是指针?
指针是一个动态变量,其值是另一个变量的地址,即内存位置的直接地址。与任何变量或常量一样,在使用指针存储任何变量地址之前,必须先声明它。指针变量声明的一般形式为:
type ptr-identifier = ^base-variable-type;
指针类型通过在基本类型前添加向上箭头或插入符号 (^) 来定义。基本类型定义数据项的类型。一旦定义了指针变量的类型,它只能指向该类型的项。定义指针类型后,我们可以使用 **var** 声明来声明指针变量。
var p1, p2, ... : ptr-identifier;
以下是一些有效的指针声明:
type
Rptr = ^real;
Cptr = ^char;
Bptr = ^ Boolean;
Aptr = ^array[1..5] of real;
date-ptr = ^ date;
Date = record
Day: 1..31;
Month: 1..12;
Year: 1900..3000;
End;
var
a, b : Rptr;
d: date-ptr;
通过使用相同的插入符号 (^) 来取消引用指针变量。例如,指针 rptr 引用的关联变量是 rptr^。可以这样访问:
rptr^ := 234.56;
以下示例将说明此概念:
program exPointers;
var
number: integer;
iptr: ^integer;
begin
number := 100;
writeln('Number is: ', number);
iptr := @number;
writeln('iptr points to a value: ', iptr^);
iptr^ := 200;
writeln('Number is: ', number);
writeln('iptr points to a value: ', iptr^);
end.
当编译并执行上述代码时,它会产生以下结果:
Number is: 100 iptr points to a value: 100 Number is: 200 iptr points to a value: 200
在 Pascal 中打印内存地址
在 Pascal 中,我们可以使用地址运算符 (@) 将变量的地址赋给指针变量。我们使用此指针来操作和访问数据项。但是,如果由于某种原因,我们需要处理内存地址本身,我们需要将其存储在字类型变量中。
让我们扩展上面的示例以打印存储在指针 iptr 中的内存地址:
program exPointers;
var
number: integer;
iptr: ^integer;
y: ^word;
begin
number := 100;
writeln('Number is: ', number);
iptr := @number;
writeln('iptr points to a value: ', iptr^);
iptr^ := 200;
writeln('Number is: ', number);
writeln('iptr points to a value: ', iptr^);
y := addr(iptr);
writeln(y^);
end.
当编译并执行上述代码时,它会产生以下结果:
Number is: 100 iptr points to a value: 100 Number is: 200 iptr points to a value: 200 45504
NIL 指针
如果您的指针没有要赋值的精确地址,始终建议将 **NIL** 值赋给指针变量。这是在变量声明时完成的。分配了 **NIL** 的指针不指向任何位置。考虑以下程序:
program exPointers;
var
number: integer;
iptr: ^integer;
y: ^word;
begin
iptr := nil;
y := addr(iptr);
writeln('the vaule of iptr is ', y^);
end.
当编译并执行上述代码时,它会产生以下结果:
The value of ptr is 0
要检查 **nil** 指针,您可以使用以下 if 语句:
if(ptr <> nill )then (* succeeds if p is not null *) if(ptr = nill)then (* succeeds if p is null *)
Pascal 指针详解
指针有很多但简单的概念,它们对 Pascal 编程非常重要。以下是一些重要的指针概念,Pascal 程序员应该清楚:
| 序号 | 概念和描述 |
|---|---|
| 1 |
Pascal - 指针运算
有四个算术运算符可用于指针:增量、减量、+、- |
| 2 |
Pascal - 指针数组
您可以定义数组来保存多个指针。 |
| 3 |
Pascal - 指向指针的指针
Pascal 允许您对指针进行指针操作,依此类推。 |
| 4 |
在 Pascal 中将指针传递给子程序
通过引用或通过地址传递参数,都能使被调用子程序在调用子程序中更改传递的参数。 |
| 5 |
Pascal 中子程序的返回指针
Pascal 允许子程序返回一个指针。 |
Pascal - 记录
Pascal 数组允许您定义可以保存几种相同类型数据项的变量类型,但记录是 Pascal 中另一种用户定义的数据类型,它允许您组合不同类型的数据项。
记录由不同的字段组成。假设您想跟踪图书馆中的书籍,您可能希望跟踪每本书的以下属性:
- 标题
- 作者
- 主题
- 图书 ID
定义记录
要定义记录类型,您可以使用类型声明语句。记录类型定义如下:
type record-name = record field-1: field-type1; field-2: field-type2; ... field-n: field-typen; end;
以下是声明 Book 记录的方法:
type Books = record title: packed array [1..50] of char; author: packed array [1..50] of char; subject: packed array [1..100] of char; book_id: integer; end;
记录变量以通常的方式定义为
var r1, r2, ... : record-name;
或者,您可以直接定义记录类型变量,如下所示:
var Books : record title: packed array [1..50] of char; author: packed array [1..50] of char; subject: packed array [1..100] of char; book_id: integer; end;
访问记录的字段
要访问记录的任何字段,我们使用成员访问运算符 (.)。成员访问运算符被编码为记录变量名和我们希望访问的字段之间的句点。以下示例说明了结构的使用:
program exRecords;
type
Books = record
title: packed array [1..50] of char;
author: packed array [1..50] of char;
subject: packed array [1..100] of char;
book_id: longint;
end;
var
Book1, Book2: Books; (* Declare Book1 and Book2 of type Books *)
begin
(* book 1 specification *)
Book1.title := 'C Programming';
Book1.author := 'Nuha Ali ';
Book1.subject := 'C Programming Tutorial';
Book1.book_id := 6495407;
(* book 2 specification *)
Book2.title := 'Telecom Billing';
Book2.author := 'Zara Ali';
Book2.subject := 'Telecom Billing Tutorial';
Book2.book_id := 6495700;
(* print Book1 info *)
writeln ('Book 1 title : ', Book1.title);
writeln('Book 1 author : ', Book1.author);
writeln( 'Book 1 subject : ', Book1.subject);
writeln( 'Book 1 book_id : ', Book1.book_id);
writeln;
(* print Book2 info *)
writeln ('Book 2 title : ', Book2.title);
writeln('Book 2 author : ', Book2.author);
writeln( 'Book 2 subject : ', Book2.subject);
writeln( 'Book 2 book_id : ', Book2.book_id);
end.
当编译并执行上述代码时,它会产生以下结果:
Book 1 title : C Programming Book 1 author : Nuha Ali Book 1 subject : C Programming Tutorial Book 1 book_id : 6495407 Book 2 title : Telecom Billing Book 2 author : Zara Ali Book 2 subject : Telecom Billing Tutorial Book 2 book_id : 6495700
记录作为子程序参数
您可以像传递任何其他变量或指针一样传递记录作为子程序参数。您将以与在上述示例中访问相同的方式访问记录字段:
program exRecords;
type
Books = record
title: packed array [1..50] of char;
author: packed array [1..50] of char;
subject: packed array [1..100] of char;
book_id: longint;
end;
var
Book1, Book2: Books; (* Declare Book1 and Book2 of type Books *)
(* procedure declaration *)
procedure printBook( var book: Books );
begin
(* print Book info *)
writeln ('Book title : ', book.title);
writeln('Book author : ', book.author);
writeln( 'Book subject : ', book.subject);
writeln( 'Book book_id : ', book.book_id);
end;
begin
(* book 1 specification *)
Book1.title := 'C Programming';
Book1.author := 'Nuha Ali ';
Book1.subject := 'C Programming Tutorial';
Book1.book_id := 6495407;
(* book 2 specification *)
Book2.title := 'Telecom Billing';
Book2.author := 'Zara Ali';
Book2.subject := 'Telecom Billing Tutorial';
Book2.book_id := 6495700;
(* print Book1 info *)
printbook(Book1);
writeln;
(* print Book2 info *)
printbook(Book2);
end.
当编译并执行上述代码时,它会产生以下结果:
Book 1 title : C Programming Book 1 author : Nuha Ali Book 1 subject : C Programming Tutorial Book 1 book_id : 6495407 Book 2 title : Telecom Billing Book 2 author : Zara Ali Book 2 subject : Telecom Billing Tutorial Book 2 book_id : 6495700
指向记录的指针
您可以像定义指向任何其他变量的指针一样定义指向记录的指针,如下所示:
type record-ptr = ^ record-name; record-name = record field-1: field-type1; field-2: field-type2; ... field-n: field-typen; end;
现在,您可以在上述定义的指针变量中存储记录类型变量的地址。要声明创建的指针类型的变量,请使用 var 关键字:
var r1, r2, ... : record-ptr;
在使用这些指针之前,必须为记录名类型变量创建存储空间,这些指针将操作这些存储空间。
new(r1); new(r2);
要使用指向该记录的指针访问记录的成员,必须使用 ^ 运算符,如下所示:
r1^.feild1 := value1; r1^.feild2 := value2; ... r1^fieldn := valuen;
最后,不要忘记在不再使用时释放已使用的存储空间:
dispose(r1); dispose(r2);
让我们使用指向 Books 记录的指针重写第一个示例。希望这将更容易理解这个概念:
program exRecords;
type
BooksPtr = ^ Books;
Books = record
title: packed array [1..50] of char;
author: packed array [1..50] of char;
subject: packed array [1..100] of char;
book_id: longint;
end;
var
(* Declare Book1 and Book2 of pointer type that refers to Book type *)
Book1, Book2: BooksPtr;
begin
new(Book1);
new(book2);
(* book 1 specification *)
Book1^.title := 'C Programming';
Book1^.author := 'Nuha Ali ';
Book1^.subject := 'C Programming Tutorial';
Book1^.book_id := 6495407;
(* book 2 specification *)
Book2^.title := 'Telecom Billing';
Book2^.author := 'Zara Ali';
Book2^.subject := 'Telecom Billing Tutorial';
Book2^.book_id := 6495700;
(* print Book1 info *)
writeln ('Book 1 title : ', Book1^.title);
writeln('Book 1 author : ', Book1^.author);
writeln( 'Book 1 subject : ', Book1^.subject);
writeln( 'Book 1 book_id : ', Book1^.book_id);
(* print Book2 info *)
writeln ('Book 2 title : ', Book2^.title);
writeln('Book 2 author : ', Book2^.author);
writeln( 'Book 2 subject : ', Book2^.subject);
writeln( 'Book 2 book_id : ', Book2^.book_id);
dispose(Book1);
dispose(Book2);
end.
当编译并执行上述代码时,它会产生以下结果:
Book 1 title : C Programming Book 1 author : Nuha Ali Book 1 subject : C Programming Tutorial Book 1 book_id : 6495407 Book 2 title : Telecom Billing Book 2 author : Zara Ali Book 2 subject : Telecom Billing Tutorial Book 2 book_id : 6495700
With 语句
我们已经讨论过可以使用成员访问运算符 (.) 访问记录的成员。这样每次都必须写记录变量的名称。With 语句提供了一种替代方法来做到这一点。
查看以下从我们的第一个示例中获取的代码片段:
(* book 1 specification *) Book1.title := 'C Programming'; Book1.author := 'Nuha Ali '; Book1.subject := 'C Programming Tutorial'; Book1.book_id := 6495407;
可以使用 With 语句将相同的赋值写成:
(* book 1 specification *) With Book1 do begin title := 'C Programming'; author := 'Nuha Ali '; subject := 'C Programming Tutorial'; book_id := 6495407; end;
Pascal - 变体
Pascal 支持一种名为变体的独特存储类型。您可以在变体变量中分配任何简单类型的值。存储在变体中的值的类型仅在运行时确定。几乎任何简单类型都可以分配给变体:序数类型、字符串类型、int64 类型。
集合、记录、数组、文件、对象和类等结构化类型与变体不兼容。您还可以将指针分配给变体。
Free Pascal 支持变体。
声明变体
您可以使用 var 关键字像声明任何其他类型一样声明变体类型。声明变体类型的语法如下:
var v: variant;
现在,此变体变量 v 可以分配给几乎所有简单类型,包括枚举类型,反之亦然。
type color = (red, black, white); var v : variant; i : integer; b : byte; w : word; q : int64; e : extended; d : double; en : color; as : ansistring; ws : widestring; begin v := i; v := b; v := w; v := q; v := e; v := en; v := d: v := as; v := ws; end;
示例
以下示例将说明此概念:
Program exVariant;
uses variants;
type
color = (red, black, white);
var
v : variant;
i : integer;
r: real;
c : color;
as : ansistring;
begin
i := 100;
v:= i;
writeln('Variant as Integer: ', v);
r:= 234.345;
v:= r;
writeln('Variant as real: ', v);
c := red;
v := c;
writeln('Variant as Enumerated data: ', v);
as:= ' I am an AnsiString';
v:= as;
writeln('Variant as AnsiString: ', v);
end.
当编译并执行上述代码时,它会产生以下结果:
Variant as Integer: 100 Variant as real: 234.345 Variant as Enumerated data: 0 Variant as AnsiString: I am an AnsiString
Pascal - 集合
集合是相同类型元素的集合。Pascal 允许定义集合数据类型。集合中的元素称为其成员。在数学中,集合用花括号{}括起成员来表示。但是,在 Pascal 中,集合元素用方括号 [] 括起来,称为集合构造器。
定义集合类型和变量
Pascal 集合类型定义如下
type set-identifier = set of base type;
集合类型的变量定义如下
var s1, s2, ...: set-identifier;
或,
s1, s2...: set of base type;
一些有效集合类型声明的示例:
type Days = (mon, tue, wed, thu, fri, sat, sun); Letters = set of char; DaySet = set of days; Alphabets = set of 'A' .. 'Z'; studentAge = set of 13..20;
集合运算符
您可以在 Pascal 集合上执行以下集合操作。
| 序号 | 操作与描述 |
|---|---|
| 1 |
并集 这将两个集合连接起来,并生成一个包含两个集合中成员的新集合。 |
| 2 |
差集 获取两个集合的差集,并生成一个不包含两个集合共有元素的新集合。 |
| 3 |
交集 获取两个集合的交集,并生成一个包含两个集合共有元素的新集合。 |
| 4 |
包含 如果集合 P 中的所有项目也都在集合 Q 中,但反之则不然,则集合 P 包含在集合 Q 中。 |
| 5 |
对称差 获取两个集合的对称差,并生成一个包含任一集合中元素但不包含其交集中元素的集合。 |
| 6 |
In 它检查成员资格。 |
下表显示了 Free Pascal 支持的所有集合运算符。假设S1和S2是两个字符集,使得:
S1 := ['a', 'b', 'c'];
S2 := ['c', 'd', 'e'];
| 运算符 | 描述 | 示例 |
|---|---|---|
| + | 两个集合的并集 | S1 + S2 将生成一个集合 ['a', 'b', 'c', 'd', 'e'] |
| - | 两个集合的差集 | S1 - S2 将生成一个集合 ['a', 'b'] |
| * | 两个集合的交集 | S1 * S2 将生成一个集合 ['c'] |
| >< | 两个集合的对称差 | S1 >< S2 将生成一个集合 ['a', 'b', 'd', 'e'] |
| = | 检查两个集合是否相等 | S1 = S2 将返回布尔值 False |
| <> | 检查两个集合是否不相等 | S1 <> S2 将返回布尔值 True |
| <= | 包含(检查一个集合是否为另一个集合的子集) | S1 <= S2 将返回布尔值 False |
| 包含 | 将元素包含在集合中;基本上是集合和相同基类型的元素的并集 | Include (S1, ['d']) 将生成一个集合 ['a', 'b', 'c', 'd'] |
| 排除 | 从集合中排除元素;基本上是集合和相同基类型的元素的差集 | Exclude (S2, ['d']) 将生成一个集合 ['c', 'e'] |
| In | 检查集合中元素的集合成员资格 | ['e'] in S2 返回布尔值 True |
示例
以下示例说明了某些运算符的使用:
program setColors;
type
color = (red, blue, yellow, green, white, black, orange);
colors = set of color;
procedure displayColors(c : colors);
const
names : array [color] of String[7]
= ('red', 'blue', 'yellow', 'green', 'white', 'black', 'orange');
var
cl : color;
s : String;
begin
s:= ' ';
for cl:=red to orange do
if cl in c then
begin
if (s<>' ') then s :=s +' , ';
s:=s+names[cl];
end;
writeln('[',s,']');
end;
var
c : colors;
begin
c:= [red, blue, yellow, green, white, black, orange];
displayColors(c);
c:=[red, blue]+[yellow, green];
displayColors(c);
c:=[red, blue, yellow, green, white, black, orange] - [green, white];
displayColors(c);
c:= [red, blue, yellow, green, white, black, orange]*[green, white];
displayColors(c);
c:= [red, blue, yellow, green]><[yellow, green, white, black];
displayColors(c);
end.
当编译并执行上述代码时,它会产生以下结果:
[ red , blue , yellow , green , white , black , orange] [ red , blue , yellow , green] [ red , blue , yellow , black , orange] [ green , white] [ red , blue , white , black]
Pascal - 文件处理
Pascal 将文件视为组件的序列,这些组件必须具有统一的类型。文件的类型由组件的类型决定。文件数据类型定义如下:
type file-name = file of base-type;
其中,base-type 指示文件的组件类型。基类型可以是任何类型,例如整数、实数、布尔值、枚举、子范围、记录、数组和集合,但不能是另一种文件类型。使用var声明创建文件类型的变量:
var f1, f2,...: file-name;
以下是一些定义文件类型和文件变量的示例:
type rfile = file of real; ifile = file of integer; bfile = file of boolean; datafile = file of record arrfile = file of array[1..4] of integer; var marks: arrfile; studentdata: datafile; rainfalldata: rfile; tempdata: ifile; choices: bfile;
创建和写入文件
让我们编写一个程序,为学生的记录创建数据文件。它将创建一个名为 students.dat 的文件并将学生数据写入其中:
program DataFiles;
type
StudentRecord = Record
s_name: String;
s_addr: String;
s_batchcode: String;
end;
var
Student: StudentRecord;
f: file of StudentRecord;
begin
Assign(f,'students.dat');
Rewrite(f);
Student.s_name := 'John Smith';
Student.s_addr := 'United States of America';
Student.s_batchcode := 'Computer Science';
Write(f,Student);
Close(f);
end.
编译并运行后,程序将在工作目录中创建一个名为students.dat的文件。您可以使用文本编辑器(如记事本)打开文件以查看 John Smith 的数据。
从文件读取
我们刚刚创建了一个名为 students.dat 的文件并向其中写入数据。现在,让我们编写一个程序,从文件中读取学生数据:
program DataFiles;
type
StudentRecord = Record
s_name: String;
s_addr: String;
s_batchcode: String;
end;
var
Student: StudentRecord;
f: file of StudentRecord;
begin
assign(f, 'students.dat');
reset(f);
while not eof(f) do
begin
read(f,Student);
writeln('Name: ',Student.s_name);
writeln('Address: ',Student.s_addr);
writeln('Batch Code: ', Student.s_batchcode);
end;
close(f);
end.
当编译并执行上述代码时,它会产生以下结果:
Name: John Smith Address: United States of America Batch Code: Computer Science
文件作为子程序参数
Pascal 允许在标准和用户定义的子程序中使用文件变量作为参数。以下示例说明了此概念。该程序创建了一个名为 rainfall.txt 的文件并存储了一些降雨数据。接下来,它打开文件,读取数据并计算平均降雨量。
请注意,如果将文件参数与子程序一起使用,则必须将其声明为 var 参数。
program addFiledata;
const
MAX = 4;
type
raindata = file of real;
var
rainfile: raindata;
filename: string;
procedure writedata(var f: raindata);
var
data: real;
i: integer;
begin
rewrite(f, sizeof(data));
for i:=1 to MAX do
begin
writeln('Enter rainfall data: ');
readln(data);
write(f, data);
end;
close(f);
end;
procedure computeAverage(var x: raindata);
var
d, sum: real;
average: real;
begin
reset(x);
sum:= 0.0;
while not eof(x) do
begin
read(x, d);
sum := sum + d;
end;
average := sum/MAX;
close(x);
writeln('Average Rainfall: ', average:7:2);
end;
begin
writeln('Enter the File Name: ');
readln(filename);
assign(rainfile, filename);
writedata(rainfile);
computeAverage(rainfile);
end.
当编译并执行上述代码时,它会产生以下结果:
Enter the File Name: rainfall.txt Enter rainfall data: 34 Enter rainfall data: 45 Enter rainfall data: 56 Enter rainfall data: 78 Average Rainfall: 53.25
文本文件
在 Pascal 中,文本文件由字符行组成,每行以换行符结尾。您可以声明和定义此类文件,如下所示:
type file-name = text;
字符的普通文件与文本文件之间的区别在于,文本文件被分成行,每行都由系统自动插入的特殊换行符终止。以下示例创建并写入名为 contact.txt 的文本文件:
program exText;
var
filename, data: string;
myfile: text;
begin
writeln('Enter the file name: ');
readln(filename);
assign(myfile, filename);
rewrite(myfile);
writeln(myfile, 'Note to Students: ');
writeln(myfile, 'For details information on Pascal Programming');
writeln(myfile, 'Contact: Tutorials Point');
writeln('Completed writing');
close(myfile);
end.
当编译并执行上述代码时,它会产生以下结果:
Enter the file name: contact.txt Completed writing
追加到文件
追加到文件表示写入已存在一些数据的文件,而不会覆盖该文件。以下程序说明了这一点:
program exAppendfile;
var
myfile: text;
info: string;
begin
assign(myfile, 'contact.txt');
append(myfile);
writeln('Contact Details');
writeln('webmaster@tutorialspoint.com');
close(myfile);
(* let us read from this file *)
assign(myfile, 'contact.txt');
reset(myfile);
while not eof(myfile) do
begin
readln(myfile, info);
writeln(info);
end;
close(myfile);
end.
当编译并执行上述代码时,它会产生以下结果:
Contact Details webmaster@tutorialspoint.com Note to Students: For details information on Pascal Programming Contact: Tutorials Point
文件处理函数
Free Pascal 提供以下用于文件处理的函数/过程:
| 序号 | 函数名称与描述 |
|---|---|
| 1 |
procedure Append(var t: Text); 以追加模式打开文件 |
| 2 |
procedure Assign(out f: file; const Name:); 为文件分配名称 |
| 3 |
procedure Assign(out f: file; p: PChar); 为文件分配名称 |
| 4 |
procedure Assign(out f: file; c: Char); 为文件分配名称 |
| 5 |
procedure Assign(out f: TypedFile; const Name:); 为文件分配名称 |
| 6 |
procedure Assign(out f: TypedFile; p: PChar); 为文件分配名称 |
| 7 |
procedure Assign(out f: TypedFile; c: Char); 为文件分配名称 |
| 8 |
procedure Assign(out t: Text; const s:); 为文件分配名称 |
| 9 |
procedure Assign(out t: Text; p: PChar); 为文件分配名称 |
| 10 |
procedure Assign(out t: Text; c: Char); 为文件分配名称 |
| 11 |
procedure BlockRead(var f: file; var Buf; count: Int64; var Result: Int64); 将文件中的数据读入内存 |
| 12 |
procedure BlockRead(var f: file; var Buf; count: LongInt; var Result: LongInt); 将文件中的数据读入内存 |
| 13 |
procedure BlockRead(var f: file; var Buf; count: Cardinal; var Result: Cardinal); 将文件中的数据读入内存 |
| 14 |
procedure BlockRead(var f: file; var Buf; count: Word; var Result: Word); 将文件中的数据读入内存 |
| 15 |
procedure BlockRead(var f: file; var Buf; count: Word; var Result: Integer); 将文件中的数据读入内存 |
| 16 |
procedure BlockRead(var f: file; var Buf; count: Int64); 将文件中的数据读入内存 |
| 17 |
procedure BlockWrite(var f: file; const Buf; Count: Int64; var Result: Int64); 将内存中的数据写入文件 |
| 18 |
procedure BlockWrite(var f: file; const Buf; Count: LongInt; var Result: LongInt); 将内存中的数据写入文件 |
| 19 |
procedure BlockWrite(var f: file; const Buf; Count: Cardinal; var Result: Cardinal); 将内存中的数据写入文件 |
| 20 |
procedure BlockWrite(var f: file; const Buf; Count: Word; var Result: Word); 将内存中的数据写入文件 |
| 21 |
procedure BlockWrite(var f: file; const Buf; Count: Word; var Result: Integer); 将内存中的数据写入文件 |
| 22 |
procedure BlockWrite(var f: file; const Buf; Count: LongInt); 将内存中的数据写入文件 |
| 23 |
procedure Close(var f: file); 关闭文件 |
| 24 |
procedure Close(var t: Text); 关闭文件 |
| 25 |
function EOF(var f: file):Boolean; 检查文件结尾 |
| 26 |
function EOF(var t: Text):Boolean; 检查文件结尾 |
| 27 |
function EOF: Boolean; 检查文件结尾 |
| 28 |
function EOLn(var t: Text):Boolean; 检查行结尾 |
| 29 |
function EOLn: Boolean; 检查行结尾 |
| 30 |
procedure Erase(var f: file); 从磁盘删除文件 |
| 31 |
procedure Erase(var t: Text); 从磁盘删除文件 |
| 32 |
function FilePos( var f: file):Int64; 文件中的位置 |
| 33 |
function FileSize(var f: file):Int64; 文件大小 |
| 34 |
procedure Flush(var t: Text); 将文件缓冲区写入磁盘 |
| 35 |
function IOResult: Word; 返回上次文件IO操作的结果 |
| 36 |
procedure Read(var F: Text; Args: Arguments); 从文件读取到变量中 |
| 37 |
procedure Read(Args: Arguments); 从文件读取到变量中 |
| 38 |
procedure ReadLn(var F: Text; Args: Arguments); 从文件读取到变量中并转到下一行 |
| 39 |
procedure ReadLn(Args: Arguments); 从文件读取到变量中并转到下一行 |
| 40 |
procedure Rename(var f: file; const s:); 重命名磁盘上的文件 |
| 41 |
procedure Rename(var f: file; p: PChar); 重命名磁盘上的文件 |
| 42 |
procedure Rename(var f: file; c: Char); 重命名磁盘上的文件 |
| 43 |
procedure Rename(var t: Text; const s); 重命名磁盘上的文件 |
| 44 |
procedure Rename(var t: Text; p: PChar); 重命名磁盘上的文件 |
| 45 |
procedure Rename( var t: Text; c: Char); 重命名磁盘上的文件 |
| 46 |
procedure Reset(var f: file; l: LongInt); 打开文件以进行读取 |
| 47 |
procedure Reset(var f: file); 打开文件以进行读取 |
| 48 |
procedure Reset(var f: TypedFile); 打开文件以进行读取 |
| 49 |
procedure Reset(var t: Text); 打开文件以进行读取 |
| 50 |
procedure Rewrite(var f: file; l: LongInt); 打开文件以进行写入 |
| 51 |
procedure Rewrite(var f: file); 打开文件以进行写入 |
| 52 |
procedure Rewrite(var f: TypedFile); 打开文件以进行写入 |
| 53 |
procedure Rewrite(var t: Text); 打开文件以进行写入 |
| 54 |
procedure Seek(var f: file; Pos: Int64); 设置文件位置 |
| 55 |
function SeekEOF(var t: Text):Boolean; 将文件位置设置为文件末尾 |
| 56 |
function SeekEOF: Boolean; 将文件位置设置为文件末尾 |
| 57 |
function SeekEOLn(var t: Text):Boolean; 将文件位置设置为行尾 |
| 58 |
function SeekEOLn: Boolean; 将文件位置设置为行尾 |
| 59 |
procedure SetTextBuf(var f: Text; var Buf); 设置文件缓冲区的大小 |
| 60 |
procedure SetTextBuf(var f: Text; var Buf; Size: SizeInt); 设置文件缓冲区的大小 |
| 61 |
procedure Truncate(var F: file); 在指定位置截断文件 |
| 62 |
procedure Write(Args: Arguments); 将变量写入文件 |
| 63 |
procedure Write(var F: Text; Args: Arguments); 将变量写入文件 |
| 64 |
procedure Writeln(Args: Arguments); 将变量写入文件并追加换行符 |
| 65 |
procedure WriteLn(var F: Text; Args: Arguments); 将变量写入文件并追加换行符 |
Pascal - 内存管理
本章介绍 Pascal 中的动态内存管理。Pascal 编程语言提供了几个用于内存分配和管理的函数。
动态分配内存
在进行编程时,如果您知道数组的大小,那么这很容易,您可以将其定义为数组。例如,要存储任何人的姓名,它最多可以有 100 个字符,因此您可以定义如下内容:
var name: array[1..100] of char;
但是现在,让我们考虑一种情况,您不知道需要存储的文本的长度,例如,您想存储有关某个主题的详细说明。在这里,我们需要定义一个指向字符串的指针,而无需定义需要多少内存。
Pascal 提供了一个过程 new 来创建指针变量。
program exMemory;
var
name: array[1..100] of char;
description: ^string;
begin
name:= 'Zara Ali';
new(description);
if not assigned(description) then
writeln(' Error - unable to allocate required memory')
else
description^ := 'Zara ali a DPS student in class 10th';
writeln('Name = ', name );
writeln('Description: ', description^ );
end.
当编译并执行上述代码时,它会产生以下结果:
Name = Zara Ali Description: Zara ali a DPS student in class 10th
现在,如果您需要定义一个具有特定字节数的指针,以便稍后由它引用,则应使用 getmem 函数或 getmem 过程,其语法如下:
procedure Getmem( out p: pointer; Size: PtrUInt ); function GetMem( size: PtrUInt ):pointer;
在前面的示例中,我们声明了一个指向字符串的指针。字符串的最大值为 255 个字节。如果您真的不需要那么大的空间,或者更大的空间(以字节为单位),getmem 子程序允许指定该空间。让我们使用 getmem 重写前面的示例:
program exMemory;
var
name: array[1..100] of char;
description: ^string;
begin
name:= 'Zara Ali';
description := getmem(200);
if not assigned(description) then
writeln(' Error - unable to allocate required memory')
else
description^ := 'Zara ali a DPS student in class 10th';
writeln('Name = ', name );
writeln('Description: ', description^ );
freemem(description);
end.
当编译并执行上述代码时,它会产生以下结果:
Name = Zara Ali Description: Zara ali a DPS student in class 10th
因此,您可以完全控制,并且可以在分配内存时传递任何大小的值,这与数组不同,因为一旦定义了数组的大小,就无法更改。
调整内存大小和释放内存
当您的程序退出时,操作系统会自动释放您的程序分配的所有内存,但作为一种良好的做法,当您不再需要内存时,您应该释放该内存。
Pascal 提供了过程 dispose 来使用过程 new 释放动态创建的变量。如果您使用 getmem 子程序分配了内存,则需要使用子程序 freemem 来释放此内存。freemem 子程序具有以下语法:
procedure Freemem( p: pointer; Size: PtrUInt ); function Freemem( p: pointer ):PtrUInt;
或者,您可以通过调用函数 ReAllocMem 来增加或减少已分配内存块的大小。让我们再次检查上面的程序并使用 ReAllocMem 和 freemem 子程序。以下是 ReAllocMem 的语法:
function ReAllocMem( var p: pointer; Size: PtrUInt ):pointer;
以下是一个使用 ReAllocMem 和 freemem 子程序的示例:
program exMemory;
var
name: array[1..100] of char;
description: ^string;
desp: string;
begin
name:= 'Zara Ali';
desp := 'Zara ali a DPS student.';
description := getmem(30);
if not assigned(description) then
writeln('Error - unable to allocate required memory')
else
description^ := desp;
(* Suppose you want to store bigger description *)
description := reallocmem(description, 100);
desp := desp + ' She is in class 10th.';
description^:= desp;
writeln('Name = ', name );
writeln('Description: ', description^ );
freemem(description);
end.
当编译并执行上述代码时,它会产生以下结果:
Name = Zara Ali Description: Zara ali a DPS student. She is in class 10th
内存管理函数
Pascal 提供了许多内存管理函数,这些函数用于实现各种数据结构并在 Pascal 中实现低级编程。许多这些函数是实现相关的。Free Pascal 为内存管理提供了以下函数和过程:
| 序号 | 函数名称与描述 |
|---|---|
| 1 |
function Addr(X: TAnytype):Pointer; 返回变量的地址 |
| 2 |
function Assigned(P: Pointer):Boolean; 检查指针是否有效 |
| 3 |
function CompareByte(const buf1; const buf2; len: SizeInt):SizeInt; 逐字节比较两个内存缓冲区 |
| 4 |
function CompareChar(const buf1; const buf2; len: SizeInt):SizeInt; 逐字节比较两个内存缓冲区 |
| 5 |
function CompareDWord(const buf1; const buf2; len: SizeInt):SizeInt; 逐字节比较两个内存缓冲区 |
| 6 |
function CompareWord(const buf1; const buf2; len: SizeInt):SizeInt; 逐字节比较两个内存缓冲区 |
| 7 |
function Cseg: Word; 返回代码段 |
| 8 |
procedure Dispose(P: Pointer); 释放动态分配的内存 |
| 9 |
procedure Dispose(P: TypedPointer; Des: TProcedure); 释放动态分配的内存 |
| 10 |
function Dseg: Word; 返回数据段 |
| 11 |
procedure FillByte(var x; count: SizeInt; value: Byte); 用 8 位模式填充内存区域 |
| 12 |
procedure FillChar( var x; count: SizeInt; Value: Byte|Boolean|Char); 用某个字符填充内存区域 |
| 13 |
procedure FillDWord( var x; count: SizeInt; value: DWord); 用 32 位模式填充内存区域 |
| 14 |
procedure FillQWord( var x; count: SizeInt; value: QWord); 用 64 位模式填充内存区域 |
| 15 |
procedure FillWord( var x; count: SizeInt; Value: Word);
用 16 位模式填充内存区域 |
| 16 |
procedure Freemem( p: pointer; Size: PtrUInt); 释放已分配的内存 |
| 17 |
procedure Freemem( p: pointer ); 释放已分配的内存 |
| 18 |
procedure Getmem( out p: pointer; Size: PtrUInt); 分配新内存 |
| 19 |
procedure Getmem( out p: pointer); 分配新内存 |
| 20 |
procedure GetMemoryManager( var MemMgr: TMemoryManager); 返回当前内存管理器 |
| 21 |
function High( Arg: TypeOrVariable):TOrdinal; 返回开放数组或枚举的最高索引 |
| 22 |
function IndexByte( const buf; len: SizeInt; b: Byte):SizeInt; 在内存范围内查找字节大小的值 |
| 23 |
function IndexChar( const buf; len: SizeInt; b: Char):SizeInt; 在内存范围内查找字符大小的值 |
| 24 |
function IndexDWord( const buf; len: SizeInt; b: DWord):SizeInt; 在内存范围内查找 DWord 大小(32 位)的值 |
| 25 |
function IndexQWord( const buf; len: SizeInt; b: QWord):SizeInt; 在内存范围内查找 QWord 大小的值 |
| 26 |
function Indexword( const buf; len: SizeInt; b: Word):SizeInt; 在内存范围内查找字大小的值 |
| 27 |
function IsMemoryManagerSet: Boolean; 内存管理器是否已设置 |
| 28 |
function Low( Arg: TypeOrVariable ):TOrdinal; 返回开放数组或枚举的最低索引 |
| 29 |
procedure Move( const source; var dest; count: SizeInt ); 将数据从内存中的一个位置移动到另一个位置 |
| 30 |
procedure MoveChar0( const buf1; var buf2; len: SizeInt); 移动数据直到第一个零字符 |
| 31 |
procedure New( var P: Pointer); 为变量动态分配内存 |
| 32 |
procedure New( var P: Pointer; Cons: TProcedure); 为变量动态分配内存 |
| 33 |
function Ofs( var X ):LongInt; 返回变量的偏移量 |
| 34 |
function ptr( sel: LongInt; off: LongInt):farpointer; 将段和偏移量组合成指针 |
| 35 |
function ReAllocMem( var p: pointer; Size: PtrUInt):pointer; 调整堆上内存块的大小 |
| 36 |
function Seg( var X):LongInt; 返回段 |
| 37 |
procedure SetMemoryManager( const MemMgr: TMemoryManager ); 设置内存管理器 |
| 38 |
function Sptr: Pointer; 返回当前堆栈指针 |
| 39 |
function Sseg: Word; 返回堆栈段寄存器值 |
Pascal - 单元
Pascal 程序可以由称为单元的模块组成。一个单元可能包含一些代码块,这些代码块又由变量和类型声明、语句、过程等组成。Pascal 中有很多内置单元,并且 Pascal 允许程序员定义和编写他们自己的单元,以便以后在各种程序中使用。
使用内置单元
内置单元和用户定义单元都通过 uses 子句包含在程序中。我们已经在 Pascal - 变体 教程中使用了 variants 单元。本教程解释了如何创建和包含用户定义的单元。但是,让我们首先了解如何在程序中包含内置单元 crt:
program myprog; uses crt;
以下示例说明了如何使用 crt 单元:
Program Calculate_Area (input, output);
uses crt;
var
a, b, c, s, area: real;
begin
textbackground(white); (* gives a white background *)
clrscr; (*clears the screen *)
textcolor(green); (* text color is green *)
gotoxy(30, 4); (* takes the pointer to the 4th line and 30th column)
writeln('This program calculates area of a triangle:');
writeln('Area = area = sqrt(s(s-a)(s-b)(s-c))');
writeln('S stands for semi-perimeter');
writeln('a, b, c are sides of the triangle');
writeln('Press any key when you are ready');
readkey;
clrscr;
gotoxy(20,3);
write('Enter a: ');
readln(a);
gotoxy(20,5);
write('Enter b:');
readln(b);
gotoxy(20, 7);
write('Enter c: ');
readln(c);
s := (a + b + c)/2.0;
area := sqrt(s * (s - a)*(s-b)*(s-c));
gotoxy(20, 9);
writeln('Area: ',area:10:3);
readkey;
end.
这是我们在 Pascal 教程开始时使用的相同程序,编译并运行它以查找更改的影响。
创建和使用 Pascal 单元
要创建单元,您需要编写要存储在其中的模块或子程序,并将其保存在扩展名为 .pas 的文件中。此文件的首行应以关键字 unit 后跟单元名称开头。例如:
unit calculateArea;
以下是创建 Pascal 单元的三个重要步骤:
文件名称和单元名称应完全相同。因此,我们的单元 calculateArea 将保存在名为 calculateArea.pas 的文件中。
下一行应包含单个关键字 interface。在此行之后,您将编写此单元中所有函数和过程的声明。
在函数声明之后,编写单词 implementation,它也是一个关键字。在包含关键字 implementation 的行之后,提供所有子程序的定义。
以下程序创建名为 calculateArea 的单元:
unit CalculateArea; interface function RectangleArea( length, width: real): real; function CircleArea(radius: real) : real; function TriangleArea( side1, side2, side3: real): real; implementation function RectangleArea( length, width: real): real; begin RectangleArea := length * width; end; function CircleArea(radius: real) : real; const PI = 3.14159; begin CircleArea := PI * radius * radius; end; function TriangleArea( side1, side2, side3: real): real; var s, area: real; begin s := (side1 + side2 + side3)/2.0; area := sqrt(s * (s - side1)*(s-side2)*(s-side3)); TriangleArea := area; end; end.
接下来,让我们编写一个简单的程序来使用我们上面定义的单元:
program AreaCalculation;
uses CalculateArea,crt;
var
l, w, r, a, b, c, area: real;
begin
clrscr;
l := 5.4;
w := 4.7;
area := RectangleArea(l, w);
writeln('Area of Rectangle 5.4 x 4.7 is: ', area:7:3);
r:= 7.0;
area:= CircleArea(r);
writeln('Area of Circle with radius 7.0 is: ', area:7:3);
a := 3.0;
b:= 4.0;
c:= 5.0;
area:= TriangleArea(a, b, c);
writeln('Area of Triangle 3.0 by 4.0 by 5.0 is: ', area:7:3);
end.
当编译并执行上述代码时,它会产生以下结果:
Area of Rectangle 5.4 x 4.7 is: 25.380 Area of Circle with radius 7.0 is: 153.938 Area of Triangle 3.0 by 4.0 by 5.0 is: 6.000
Pascal - 日期和时间
您编写的多数软件都需要实现某种形式的日期函数,以返回当前日期和时间。日期在日常生活中如此重要,以至于在不加思考的情况下使用它们变得很容易。Pascal 还为日期运算提供了强大的工具,使操作日期变得容易。但是,这些函数的实际名称和工作原理在不同的编译器中是不同的。
获取当前日期和时间
Pascal 的 TimeToString 函数以冒号(:)分隔的形式提供当前时间。以下示例显示了如何获取当前时间:
program TimeDemo;
uses sysutils;
begin
writeln ('Current time : ',TimeToStr(Time));
end.
编译并执行上述代码时,将产生以下结果:
Current time : 18:33:08
Date 函数以 TDateTime 格式返回当前日期。TDateTime 是一个双精度值,需要一些解码和格式化。以下程序演示了如何在程序中使用它来显示当前日期:
Program DateDemo;
uses sysutils;
var
YY,MM,DD : Word;
begin
writeln ('Date : ',Date);
DeCodeDate (Date,YY,MM,DD);
writeln (format ('Today is (DD/MM/YY): %d/%d/%d ',[dd,mm,yy]));
end.
编译并执行上述代码时,将产生以下结果:
Date: 4.111300000000000E+004 Today is (DD/MM/YY):23/7/2012
Now 函数返回当前日期和时间:
Program DatenTimeDemo;
uses sysutils;
begin
writeln ('Date and Time at the time of writing : ',DateTimeToStr(Now));
end.
编译并执行上述代码时,将产生以下结果:
Date and Time at the time of writing : 23/7/2012 18:51:
Free Pascal 提供了一个名为 TTimeStamp 的简单时间戳结构,其格式如下:
type TTimeStamp = record Time: Integer; Date: Integer; end;
各种日期和时间函数
Free Pascal 提供了以下日期和时间函数:
| 序号 | 函数名称与描述 |
|---|---|
| 1 |
function DateTimeToFileDate(DateTime: TDateTime):LongInt; 将 DateTime 类型转换为文件日期。 |
| 2 |
function DateTimeToStr( DateTime: TDateTime):; 构造 DateTime 的字符串表示形式 |
| 3 |
function DateTimeToStr(DateTime: TDateTime; const FormatSettings: TFormatSettings):; 构造 DateTime 的字符串表示形式 |
| 4 |
procedure DateTimeToString(out Result: ;const FormatStr: ;const DateTime: TDateTime); 构造 DateTime 的字符串表示形式 |
| 5 |
procedure DateTimeToString(out Result: ; const FormatStr: ; const DateTime: TDateTime; const FormatSettings: TFormatSettings); 构造 DateTime 的字符串表示形式 |
| 6 |
procedure DateTimeToSystemTime(DateTime: TDateTime; out SystemTime: TSystemTime); 将 DateTime 转换为系统时间 |
| 7 |
function DateTimeToTimeStamp( DateTime: TDateTime):TTimeStamp;将 DateTime 转换为时间戳 |
| 8 |
function DateToStr(Date: TDateTime):; 构造日期的字符串表示形式 |
| 9 |
function DateToStr(Date: TDateTime; const FormatSettings: TFormatSettings):; 构造日期的字符串表示形式 |
| 10 |
function Date: TDateTime; 获取当前日期 |
| 11 |
function DayOfWeek(DateTime: TDateTime):Integer; 获取星期几 |
| 12 |
procedure DecodeDate(Date: TDateTime; out Year: Word; out Month: Word; out Day: Word); 将 DateTime 解码为年、月和日 |
| 13 |
procedure DecodeTime(Time: TDateTime; out Hour: Word; out Minute: Word; out Second: Word; out MilliSecond: Word); 将 DateTime 解码为小时、分钟和秒 |
| 14 |
function EncodeDate(Year: Word; Month: Word; Day: Word):TDateTime; 将年份、日期和月份编码为 DateTime |
| 15 |
function EncodeTime(Hour: Word; Minute: Word; Second: Word; MilliSecond: Word):TDateTime; 将小时、分钟和秒编码为 DateTime |
| 16 |
function FormatDateTime(const FormatStr: ; DateTime: TDateTime):; 返回 DateTime 的字符串表示形式 |
| 17 |
function FormatDateTime(const FormatStr: ; DateTime: TDateTime; const FormatSettings: TFormatSettings):; 返回 DateTime 的字符串表示形式 |
| 18 |
function IncMonth(const DateTime: TDateTime; NumberOfMonths: Integer = 1):TDateTime; 将月份加 1 |
| 19 |
function IsLeapYear(Year: Word):Boolean; 确定年份是否为闰年 |
| 20 |
function MSecsToTimeStamp(MSecs: Comp):TTimeStamp; 将毫秒数转换为时间戳 |
| 21 |
function Now: TDateTime; 获取当前日期和时间 |
| 22 |
function StrToDateTime(const S:):TDateTime; 将字符串转换为 DateTime |
| 23 |
function StrToDateTime(const s: ShortString; const FormatSettings: TFormatSettings):TDateTime; 将字符串转换为 DateTime |
| 24 |
function StrToDateTime(const s: AnsiString; const FormatSettings: TFormatSettings):TDateTime; 将字符串转换为 DateTime |
| 25 |
function StrToDate(const S: ShortString):TDateTime; 将字符串转换为日期 |
| 26 |
function StrToDate(const S: Ansistring):TDateTime; 将字符串转换为日期 |
| 27 |
function StrToDate(const S: ShortString; separator: Char):TDateTime; 将字符串转换为日期 |
| 28 |
function StrToDate(const S: AnsiString; separator: Char):TDateTime; 将字符串转换为日期 |
| 29 |
function StrToDate(const S: ShortString; const useformat: ; separator: Char):TDateTime; 将字符串转换为日期 |
| 30 |
function StrToDate(const S: AnsiString; const useformat: ; separator: Char):TDateTime; 将字符串转换为日期 |
| 31 |
function StrToDate(const S: PChar; Len: Integer; const useformat: ; separator: Char = #0):TDateTime; 将字符串转换为日期 |
| 32 |
function StrToTime(const S: Shortstring):TDateTime; 将字符串转换为时间 |
| 33 |
function StrToTime(const S: Ansistring):TDateTime; 将字符串转换为时间 |
| 34 |
function StrToTime(const S: ShortString; separator: Char):TDateTime; 将字符串转换为时间 |
| 35 |
function StrToTime(const S: AnsiString; separator: Char):TDateTime; 将字符串转换为时间 |
| 36 |
function StrToTime(const S: ; FormatSettings: TFormatSettings):TDateTime; 将字符串转换为时间 |
| 37 |
function StrToTime(const S: PChar; Len: Integer; separator: Char = #0):TDateTime; 将字符串转换为时间 |
| 38 |
function SystemTimeToDateTime(const SystemTime: TSystemTime):TDateTime; 将系统时间转换为日期时间 |
| 39 |
function TimeStampToDateTime(const TimeStamp: TTimeStamp):TDateTime; 将时间戳转换为 DateTime |
| 40 |
function TimeStampToMSecs(const TimeStamp: TTimeStamp):comp; 将时间戳转换为毫秒数 |
| 41 |
function TimeToStr(Time: TDateTime):; 返回时间的字符串表示形式 |
| 42 |
function TimeToStr(Time: TDateTime; const FormatSettings: TFormatSettings):; 返回时间的字符串表示形式 |
| 43 |
function Time: TDateTime; 获取当前时间 |
以下示例说明了如何使用上述某些函数 -
Program DatenTimeDemo;
uses sysutils;
var
year, month, day, hr, min, sec, ms: Word;
begin
writeln ('Date and Time at the time of writing : ',DateTimeToStr(Now));
writeln('Today is ',LongDayNames[DayOfWeek(Date)]);
writeln;
writeln('Details of Date: ');
DecodeDate(Date,year,month,day);
writeln (Format ('Day: %d',[day]));
writeln (Format ('Month: %d',[month]));
writeln (Format ('Year: %d',[year]));
writeln;
writeln('Details of Time: ');
DecodeTime(Time,hr, min, sec, ms);
writeln (format('Hour: %d:',[hr]));
writeln (format('Minutes: %d:',[min]));
writeln (format('Seconds: %d:',[sec]));
writeln (format('Milliseconds: %d:',[hr]));
end.
编译并执行上述代码后,产生了以下结果
Date and Time at the time of writing : 7/24/2012 8:26: Today is Tuesday Details of Date: Day:24 Month:7 Year: 2012 Details of Time: Hour: 8 Minutes: 26 Seconds: 21 Milliseconds: 8
Pascal - 面向对象
我们可以想象我们的宇宙是由不同的物体组成的,例如太阳、地球、月亮等。同样,我们可以想象我们的汽车是由不同的物体组成的,例如车轮、方向盘、齿轮等。同样,存在面向对象的编程概念,它将所有事物都视为对象,并使用不同的对象实现软件。在 Pascal 中,有两种结构化数据类型用于实现现实世界中的对象 -
- 对象类型
- 类类型
面向对象的概念
在详细介绍之前,让我们定义与面向对象 Pascal 相关的重要的 Pascal 术语。
对象 - 对象是一种特殊的记录,包含像记录一样的字段;但是,与记录不同,对象包含过程和函数作为对象的一部分。这些过程和函数作为指向与对象类型关联的方法的指针来保存。
类 - 类的定义方式与对象几乎相同,但创建方式有所不同。类分配在程序的堆上,而对象分配在栈上。它是指向对象的指针,而不是对象本身。
类的实例化 - 实例化意味着创建该类类型的变量。由于类只是一个指针,因此当声明类类型的变量时,仅为指针分配内存,而不是为整个对象分配内存。只有当它使用其一个构造函数进行实例化时,才会为对象分配内存。类的实例也称为“对象”,但不要将它们与 Object Pascal 对象混淆。在本教程中,我们将为 Pascal 对象编写“Object”,为概念对象或类实例编写“object”。
成员变量 - 这些是在类或对象内部定义的变量。
成员函数 - 这些是在类或对象内部定义的函数或过程,用于访问对象数据。
成员的可见性 - 对象或类的成员也称为字段。这些字段具有不同的可见性。可见性指的是成员的可访问性,即这些成员在何处可访问。对象具有三个可见性级别:public、private 和 protected。类有五种可见性类型:public、private、strictly private、protected 和 published。我们将详细讨论可见性。
继承 - 当通过继承父类的现有功能来定义类时,则称其为继承。这里子类将继承父类所有或部分成员函数和变量。对象也可以被继承。
父类 - 被另一个类继承的类。这也被称为基类或超类。
子类 - 从另一个类继承的类。这也被称为子类或派生类。
多态性 - 这是一个面向对象的概念,其中相同的函数可以用于不同的目的。例如,函数名将保持不变,但它可能接受不同数量的参数并执行不同的任务。Pascal 类实现多态性。对象不实现多态性。
重载 - 它是多态性的一种类型,其中某些或所有运算符具有不同的实现,具体取决于其参数的类型。类似地,函数也可以被重载,具有不同的实现。Pascal 类实现重载,但对象不实现。
数据抽象 - 任何隐藏(抽象)实现细节的数据表示形式。
封装 - 指的是将所有数据和成员函数封装在一起以形成对象的概念。
构造函数 - 指的是一种特殊的函数类型,每当从类或对象形成对象时,都会自动调用该函数。
析构函数 - 指的是一种特殊的函数类型,每当对象或类被删除或超出范围时,都会自动调用该函数。
定义 Pascal 对象
对象使用类型声明进行声明。对象声明的一般形式如下 -
type object-identifier = object private field1 : field-type; field2 : field-type; ... public procedure proc1; function f1(): function-type; end; var objectvar : object-identifier;
让我们定义一个 Rectangle 对象,它有两个整数类型的数据成员 - length 和 width,以及一些用于操作这些数据成员的成员函数以及一个用于绘制矩形的过程。
type
Rectangle = object
private
length, width: integer;
public
constructor init;
destructor done;
procedure setlength(l: inteter);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
var
r1: Rectangle;
pr1: ^Rectangle;
创建对象后,您将能够调用与该对象相关的成员函数。一个成员函数将只能处理相关对象的成员变量。
以下示例显示了如何为两个矩形对象设置长度和宽度,并通过调用成员函数来绘制它们。
r1.setlength(3);
r1.setwidth(7);
writeln(' Draw a rectangle: ', r1.getlength(), ' by ' , r1.getwidth());
r1.draw;
new(pr1);
pr1^.setlength(5);
pr1^.setwidth(4);
writeln(' Draw a rectangle: ', pr1^.getlength(), ' by ' ,pr1^.getwidth());
pr1^.draw;
dispose(pr1);
以下是一个完整的示例,说明如何在 Pascal 中使用对象 -
program exObjects;
type
Rectangle = object
private
length, width: integer;
public
procedure setlength(l: integer);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
var
r1: Rectangle;
pr1: ^Rectangle;
procedure Rectangle.setlength(l: integer);
begin
length := l;
end;
procedure Rectangle.setwidth(w: integer);
begin
width :=w;
end;
function Rectangle.getlength(): integer;
begin
getlength := length;
end;
function Rectangle.getwidth(): integer;
begin
getwidth := width;
end;
procedure Rectangle.draw;
var
i, j: integer;
begin
for i:= 1 to length do
begin
for j:= 1 to width do
write(' * ');
writeln;
end;
end;
begin
r1.setlength(3);
r1.setwidth(7);
writeln('Draw a rectangle:', r1.getlength(), ' by ' , r1.getwidth());
r1.draw;
new(pr1);
pr1^.setlength(5);
pr1^.setwidth(4);
writeln('Draw a rectangle:', pr1^.getlength(), ' by ' ,pr1^.getwidth());
pr1^.draw;
dispose(pr1);
end.
当编译并执行上述代码时,它会产生以下结果:
Draw a rectangle: 3 by 7 * * * * * * * * * * * * * * * * * * * * * Draw a rectangle: 5 by 4 * * * * * * * * * * * * * * * * * * * *
对象成员的可见性
可见性指示对象成员的可访问性。Pascal 对象成员有三种可见性类型 -
| 序号 | 可见性与可访问性 |
|---|---|
| 1 |
Public 其他程序单元外部的单元可以使用这些成员 |
| 2 |
Private 这些成员仅在当前单元中可访问。 |
| 3 | Protected 这些成员仅对从父对象派生的对象可用。 |
默认情况下,对象的字段和方法是公开的,并在当前单元之外导出。
Pascal 对象的构造函数和析构函数 -
构造函数是特殊的类型方法,每当创建对象时都会自动调用它们。您只需使用关键字 constructor 声明一个方法即可在 Pascal 中创建构造函数。按照惯例,方法名称为 Init,但是,您可以提供您自己的任何有效标识符。您可以将任意数量的参数传递给构造函数。
析构函数是在对象销毁期间调用的方法。析构函数销毁构造函数创建的任何内存分配。
以下示例将为 Rectangle 类提供构造函数和析构函数,该构造函数将在对象创建时初始化矩形的长度和宽度,并在其超出范围时销毁它。
program exObjects;
type
Rectangle = object
private
length, width: integer;
public
constructor init(l, w: integer);
destructor done;
procedure setlength(l: integer);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
var
r1: Rectangle;
pr1: ^Rectangle;
constructor Rectangle.init(l, w: integer);
begin
length := l;
width := w;
end;
destructor Rectangle.done;
begin
writeln(' Desctructor Called');
end;
procedure Rectangle.setlength(l: integer);
begin
length := l;
end;
procedure Rectangle.setwidth(w: integer);
begin
width :=w;
end;
function Rectangle.getlength(): integer;
begin
getlength := length;
end;
function Rectangle.getwidth(): integer;
begin
getwidth := width;
end;
procedure Rectangle.draw;
var
i, j: integer;
begin
for i:= 1 to length do
begin
for j:= 1 to width do
write(' * ');
writeln;
end;
end;
begin
r1.init(3, 7);
writeln('Draw a rectangle:', r1.getlength(), ' by ' , r1.getwidth());
r1.draw;
new(pr1, init(5, 4));
writeln('Draw a rectangle:', pr1^.getlength(), ' by ',pr1^.getwidth());
pr1^.draw;
pr1^.init(7, 9);
writeln('Draw a rectangle:', pr1^.getlength(), ' by ' ,pr1^.getwidth());
pr1^.draw;
dispose(pr1);
r1.done;
end.
当编译并执行上述代码时,它会产生以下结果:
Draw a rectangle: 3 by 7 * * * * * * * * * * * * * * * * * * * * * Draw a rectangle: 5 by 4 * * * * * * * * * * * * * * * * * * * * Draw a rectangle: 7 by 9 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Destructor Called
Pascal 对象的继承
Pascal 对象可以选择从父对象继承。以下程序说明了 Pascal 对象中的继承。让我们创建另一个名为 TableTop 的对象,它从 Rectangle 对象继承。
program exObjects;
type
Rectangle = object
private
length, width: integer;
public
procedure setlength(l: integer);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
TableTop = object (Rectangle)
private
material: string;
public
function getmaterial(): string;
procedure setmaterial( m: string);
procedure displaydetails;
procedure draw;
end;
var
tt1: TableTop;
procedure Rectangle.setlength(l: integer);
begin
length := l;
end;
procedure Rectangle.setwidth(w: integer);
begin
width :=w;
end;
function Rectangle.getlength(): integer;
begin
getlength := length;
end;
function Rectangle.getwidth():integer;
begin
getwidth := width;
end;
procedure Rectangle.draw;
var
i, j: integer;
begin
for i:= 1 to length do
begin
for j:= 1 to width do
write(' * ');
writeln;
end;
end;
function TableTop.getmaterial(): string;
begin
getmaterial := material;
end;
procedure TableTop.setmaterial( m: string);
begin
material := m;
end;
procedure TableTop.displaydetails;
begin
writeln('Table Top: ', self.getlength(), ' by ' , self.getwidth());
writeln('Material: ', self.getmaterial());
end;
procedure TableTop.draw();
var
i, j: integer;
begin
for i:= 1 to length do
begin
for j:= 1 to width do
write(' * ');
writeln;
end;
writeln('Material: ', material);
end;
begin
tt1.setlength(3);
tt1.setwidth(7);
tt1.setmaterial('Wood');
tt1.displaydetails();
writeln;
writeln('Calling the Draw method');
tt1.draw();
end.
以下是要注意的重要事项 -
对象 Tabletop 已继承 Rectangle 对象的所有成员。
TableTop 中也存在 draw 方法。当使用 TableTop 对象调用 draw 方法时,将调用 TableTop 的 draw。
存在一个名为 self 的隐式实例,它引用对象的当前实例。
当编译并执行上述代码时,它会产生以下结果:
Table Top: 3 by 7 Material: Wood Calling the Draw Method * * * * * * * * * * * * * * * * * * * * * Material: Wood
Pascal - 类
您已经看到 Pascal 对象表现出面向对象范式的一些特征。它们实现了封装、数据隐藏和继承,但它们也有一些局限性。例如,Pascal 对象不参与多态性。因此,类被广泛用于在程序中实现正确的面向对象行为,尤其是在基于 GUI 的软件中。
类的定义方式与对象几乎相同,但它是指向对象的指针,而不是对象本身。从技术上讲,这意味着类分配在程序的堆上,而对象分配在栈上。换句话说,当您声明一个对象类型变量时,它将在栈上占用与对象大小一样多的空间,但是当您声明一个类类型变量时,它将始终在栈上占用指针的大小。实际的类数据将位于堆上。
定义 Pascal 类
类的声明方式与对象相同,使用类型声明。类声明的一般形式如下 -
type class-identifier = class
private
field1 : field-type;
field2 : field-type;
...
public
constructor create();
procedure proc1;
function f1(): function-type;
end;
var classvar : class-identifier;
值得注意以下重要事项 -
类定义应仅位于程序的类型声明部分。
类使用 class 关键字定义。
字段是类每个实例中存在的数据项。
方法在类的定义中声明。
Root 类中有一个预定义的构造函数 Create。每个抽象类和每个具体类都是 Root 的后代,因此所有类至少有一个构造函数。
Root 类中有一个预定义的析构函数 Destroy。每个抽象类和每个具体类都是 Root 的后代,因此所有类至少有一个析构函数。
让我们定义一个矩形类,它有两个整数类型的数据成员 - 长度和宽度,以及一些用于操作这些数据成员的成员函数,以及一个绘制矩形的过程。
type
Rectangle = class
private
length, width: integer;
public
constructor create(l, w: integer);
procedure setlength(l: integer);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
让我们编写一个完整的程序,该程序将创建一个矩形类的实例并绘制矩形。这与我们在讨论 Pascal 对象时使用的示例相同。您会发现这两个程序几乎相同,但有以下例外 -
您需要包含 {$mode objfpc} 指令以使用类。
您需要包含 {$m+} 指令以使用构造函数。
类实例化与对象实例化不同。仅声明变量不会为实例创建空间,您将使用构造函数 create 来分配内存。
以下是一个完整的示例 -
{$mode objfpc} // directive to be used for defining classes
{$m+} // directive to be used for using constructor
program exClass;
type
Rectangle = class
private
length, width: integer;
public
constructor create(l, w: integer);
procedure setlength(l: integer);
function getlength(): integer;
procedure setwidth(w: integer);
function getwidth(): integer;
procedure draw;
end;
var
r1: Rectangle;
constructor Rectangle.create(l, w: integer);
begin
length := l;
width := w;
end;
procedure Rectangle.setlength(l: integer);
begin
length := l;
end;
procedure Rectangle.setwidth(w: integer);
begin
width :=w;
end;
function Rectangle.getlength(): integer;
begin
getlength := length;
end;
function Rectangle.getwidth(): integer;
begin
getwidth := width;
end;
procedure Rectangle.draw;
var
i, j: integer;
begin
for i:= 1 to length do
begin
for j:= 1 to width do
write(' * ');
writeln;
end;
end;
begin
r1:= Rectangle.create(3, 7);
writeln(' Draw Rectangle: ', r1.getlength(), ' by ' , r1.getwidth());
r1.draw;
r1.setlength(4);
r1.setwidth(6);
writeln(' Draw Rectangle: ', r1.getlength(), ' by ' , r1.getwidth());
r1.draw;
end.
当编译并执行上述代码时,它会产生以下结果:
Draw Rectangle: 3 by 7 * * * * * * * * * * * * * * * * * * * * * Draw Rectangle: 4 by 6 * * * * * * * * * * * * * * * * * * * * * * * *
类成员的可见性
可见性指示类成员的可访问性。Pascal 类成员有五种可见性类型 -
| 序号 | 可见性与可访问性 |
|---|---|
| 1 |
Public 这些成员始终可访问。 |
| 2 |
Private 这些成员只能在包含类定义的模块或单元中访问。它们可以从类方法内部或外部访问。 |
| 3 | 严格私有 这些成员只能从类自身的方法中访问。同一单元中的其他类或后代类无法访问它们。 |
| 4 |
Protected 这与私有相同,但这些成员可供后代类型访问,即使它们在其他模块中实现。 |
| 5 | 发布 这与公共相同,但编译器会生成类型信息,如果编译器处于 {$M+} 状态,则需要这些信息来自动流式传输这些类。在发布部分中定义的字段必须是类类型。 |
Pascal 类的构造函数和析构函数
构造函数是特殊的方法,每当创建对象时都会自动调用它们。因此,我们充分利用这种行为,通过构造函数初始化许多内容。
Pascal 提供了一个名为 create() 的特殊函数来定义构造函数。您可以将任意数量的参数传递到构造函数中。
以下示例将为名为 Books 的类创建一个构造函数,并在对象创建时初始化书籍的价格和标题。
program classExample;
{$MODE OBJFPC} //directive to be used for creating classes
{$M+} //directive that allows class constructors and destructors
type
Books = Class
private
title : String;
price: real;
public
constructor Create(t : String; p: real); //default constructor
procedure setTitle(t : String); //sets title for a book
function getTitle() : String; //retrieves title
procedure setPrice(p : real); //sets price for a book
function getPrice() : real; //retrieves price
procedure Display(); // display details of a book
end;
var
physics, chemistry, maths: Books;
//default constructor
constructor Books.Create(t : String; p: real);
begin
title := t;
price := p;
end;
procedure Books.setTitle(t : String); //sets title for a book
begin
title := t;
end;
function Books.getTitle() : String; //retrieves title
begin
getTitle := title;
end;
procedure Books.setPrice(p : real); //sets price for a book
begin
price := p;
end;
function Books.getPrice() : real; //retrieves price
begin
getPrice:= price;
end;
procedure Books.Display();
begin
writeln('Title: ', title);
writeln('Price: ', price:5:2);
end;
begin
physics := Books.Create('Physics for High School', 10);
chemistry := Books.Create('Advanced Chemistry', 15);
maths := Books.Create('Algebra', 7);
physics.Display;
chemistry.Display;
maths.Display;
end.
当编译并执行上述代码时,它会产生以下结果:
Title: Physics for High School Price: 10 Title: Advanced Chemistry Price: 15 Title: Algebra Price: 7
与名为 create 的隐式构造函数类似,还有一个隐式析构函数方法 destroy,您可以使用它来释放类中使用的所有资源。
继承
Pascal 类定义可以选择从父类定义继承。语法如下 -
type childClas-identifier = class(baseClass-identifier) < members > end;
以下示例提供了一个 novels 类,它继承了 Books 类并在需求的基础上添加了更多功能。
program inheritanceExample;
{$MODE OBJFPC} //directive to be used for creating classes
{$M+} //directive that allows class constructors and destructors
type
Books = Class
protected
title : String;
price: real;
public
constructor Create(t : String; p: real); //default constructor
procedure setTitle(t : String); //sets title for a book
function getTitle() : String; //retrieves title
procedure setPrice(p : real); //sets price for a book
function getPrice() : real; //retrieves price
procedure Display(); virtual; // display details of a book
end;
(* Creating a derived class *)
type
Novels = Class(Books)
private
author: String;
public
constructor Create(t: String); overload;
constructor Create(a: String; t: String; p: real); overload;
procedure setAuthor(a: String); // sets author for a book
function getAuthor(): String; // retrieves author name
procedure Display(); override;
end;
var
n1, n2: Novels;
//default constructor
constructor Books.Create(t : String; p: real);
begin
title := t;
price := p;
end;
procedure Books.setTitle(t : String); //sets title for a book
begin
title := t;
end;
function Books.getTitle() : String; //retrieves title
begin
getTitle := title;
end;
procedure Books.setPrice(p : real); //sets price for a book
begin
price := p;
end;
function Books.getPrice() : real; //retrieves price
begin
getPrice:= price;
end;
procedure Books.Display();
begin
writeln('Title: ', title);
writeln('Price: ', price);
end;
(* Now the derived class methods *)
constructor Novels.Create(t: String);
begin
inherited Create(t, 0.0);
author:= ' ';
end;
constructor Novels.Create(a: String; t: String; p: real);
begin
inherited Create(t, p);
author:= a;
end;
procedure Novels.setAuthor(a : String); //sets author for a book
begin
author := a;
end;
function Novels.getAuthor() : String; //retrieves author
begin
getAuthor := author;
end;
procedure Novels.Display();
begin
writeln('Title: ', title);
writeln('Price: ', price:5:2);
writeln('Author: ', author);
end;
begin
n1 := Novels.Create('Gone with the Wind');
n2 := Novels.Create('Ayn Rand','Atlas Shrugged', 467.75);
n1.setAuthor('Margaret Mitchell');
n1.setPrice(375.99);
n1.Display;
n2.Display;
end.
当编译并执行上述代码时,它会产生以下结果:
Title: Gone with the Wind Price: 375.99 Author: Margaret Mitchell Title: Atlas Shrugged Price: 467.75 Author: Ayn Rand
值得注意以下重要事项 -
Books 类的成员具有 **受保护** 的可见性。
Novels 类有两个构造函数,因此 **重载** 运算符用于函数重载。
Books.Display 过程已声明为 **虚拟**,以便来自 Novels 类的相同方法可以 **覆盖** 它。
Novels.Create 构造函数使用 **inherited** 关键字调用基类构造函数。
接口
接口旨在为实现者提供一个通用的函数名称。不同的实现者可以根据自己的需求实现这些接口。可以说,接口是骨架,由开发人员实现。以下是一个接口示例 -
type
Mail = Interface
Procedure SendMail;
Procedure GetMail;
end;
Report = Class(TInterfacedObject, Mail)
Procedure SendMail;
Procedure GetMail;
end;
请注意,当一个类实现一个接口时,它应该实现接口的所有方法。如果未实现接口的方法,则编译器将报错。
抽象类
抽象类是指不能被实例化,只能被继承的类。抽象类通过在类定义中包含单词符号 abstract 来指定,如下所示 -
type
Shape = ABSTRACT CLASS (Root)
Procedure draw; ABSTRACT;
...
end;
从抽象类继承时,必须由子类定义父类声明中标记为抽象的所有方法;此外,这些方法必须使用相同的可见性定义。
Static 关键字
将类成员或方法声明为静态使其无需实例化类即可访问。声明为静态的成员不能使用实例化类对象访问(尽管静态方法可以)。以下示例说明了这个概念 -
program StaticExample;
{$mode objfpc}
{$static on}
type
myclass=class
num : integer;static;
end;
var
n1, n2 : myclass;
begin
n1:= myclass.create;
n2:= myclass.create;
n1.num := 12;
writeln(n2.num);
n2.num := 31;
writeln(n1.num);
writeln(myclass.num);
myclass.num := myclass.num + 20;
writeln(n1.num);
writeln(n2.num);
end.
当编译并执行上述代码时,它会产生以下结果:
12 31 31 51 51
您必须使用指令 {$static on} 来使用静态成员。