1.1 为什么选择Delphi
Delphi是美国Borland公司推出的一种基于客户/服务器体系的Windows快速应用开发工具(RAD Rapid Application Development),是一种面向对象的可视化编程工具,即根据Delphi的可视性,又结合Object Pascal 语言的编程技巧,可以开发出功能强大的Windows应用程序和数据库应用程序。 Delphi是第一个集可视化开发环境、优化的源代码编译器和可扩展的数据库访问引擎于一身的Windows开发工具。它具有以下优点:
1.优秀的可视化开发环境
2.高效率的编译器
3.结构良好的编程语言
4.对数据库和网络编程的灵活支持
5.层次清晰和可扩展的框架
1.2 Delphi 发展史
Delphi发展至今,从Delphi1、Delphi2到现在的Delphi xe,不断添加和改进各种特性,功能越来越强大。
Delphi 1.0
1995年一个开发工具中的超级明星在Borland诞生了,这就是 Delphi 1.0。在Delphi1.0中Borland放弃了OWL(Object Window Library),取而带之的是全新的Visual Component Library,从此开始了组件(Component)技术的时代,其意义深远;Delphi1.0是完全面向对象的。它是Delphi的最早版本。
Delphi 2.0
1996年Delphi2.0完成了16位到32位的跨越,提供了32位操作系统的完整支持,只能在Windows 95以上的操作系统中使用,它如同Delphi 1.0一样大获成功。
在Delphi2.0中Borland为它增加了可视的Form的继承,并且面向对象更彻底。由于所有函数支持"虚函数"特性,对程序编写和维护非常方便,大量类似的报表也采用了此技术。
Delphi 2.0中,增加了Data Modules的概念,可以将数据包装在一个模块中,在系统启动时或空闲时 将它打开,这样,所有使用这些Table的模块都可以公用它,避免重复打开和关闭。并且,由于所有数据Table位于一个模块中,非常便于管理维护和迁移升级。
Delphi 3.0
1997年:在微软COM/DCOM技术日益成熟的情况和企业对分布式应用程序开发工具的需求下,Borland的开发人员巧妙的平衡了二者的关系,使Delphi3.0成为Windows平台的第一款提供分布式开发的开发工具。
Delphi 4.0
1998年:由于决策的错误,Delphi 4.0是一个不成熟的产品,其中有大量的bug,尽管Borland也不停的发补丁,但不稳定的恶名很快在delphi用户传开, delphi4.0给delphi蒙上了阴影,也使Visual Basic有了喘息之机。
Delphi 5.0
1999年:在失败的Delphi4以后,Borland小心的推出了Delphi5.0,重新建立delphi的声望,delphi受到delphi开发人员一致推崇。在这个版本中Delphi对IDE(集成开发环境)进行了很多改进,扩展了对数据库的支持(ADO和InterBase数据库),转换功能,框架概念以及很多的新组件与新特性。
Delphi 6.0
2001年:Delphi 6添加了对如下特性的支持:对CLX(Component Library for Cross-Platform CLX)跨平台开发的支持,扩展的运行库(run-time library),dbExpress数据库引擎,Web 服务和杰出的XML支持,一个强大的Web开发框架,IDE的更多增强,大量的组件和类,delphi开始为向.net过渡做准备。
Delphi 7.0
2002年:Delphi 7是Delphi向.net过渡的产品,在照顾老的使用者的同时,Borland在其中加入了对.net 的支持,所以Delphi7可以同时编写原windows下和.net下的应用程序。2002年11月,borland为delphi7提供了修改后的vcl.net,使vcl组件可以在.net环境下使用。
Delphi 8.0
2003年:Delphi 8 for .NET集成开发环境提供了许多工具和特性以帮助你快速创建强大的.NET应用程序。它是为了与微软的visual studio. Net竟争而设计的。Delphi 8 for .NET已经拥有C#的能力,同时仍然保留Delphi的易用性可以,但它只是一个测试版,一个过渡版。还不太完善。
Delphi 9.0(2005)
2004年:Delphi9集成了starteam,caliberrm,Unit testing及Together部份的功能. 加入了inline及for in loop等功能。 它把Win32的开发工具全部整合到Delphi9中。Delphi9把Borland Delphi .Net、Borland Delphi Win32、Borland C#等环境和功能集成成一个开发工具,因此可以在Win32和.NET开发环境中切换或同时进行。
2005 10.0 发布名称:Borland Developer Studio(BDS) 2006。集成C++ Builder;
ECO(Enterprise Core Objects)升级到ECO III; 集成Together for Delphi,可以在同一个IDE中进行UML开发;QA Audits和QA Metrics可以快速的把握专案的设计和代码的质量。
2006 Turbo Borland将BDS 2006拆分成几个的版本(Delphi for win32、Delphi for .net、C#、C++ Builder),而且不能同时安装两个不同的版本。由于Borland的IDE生产部份成为一家名为codegear的公司,所以这个版本是以Borland名义推出的最后一个版本。
2007 11.0 正式名称:CodeGear RAD Studio - Delphi 2007。
2008 5.7 Borland正式宣布将CodeGear子公司出售给Embarcadero(易博龙)技术公司。
2008 8.25 Embarcadero发布CodeGear Delphi 2009 Pre-release版。
2009 8.25 Embarcadero发布CodeGear.RAD.Studio.2010版
2010 年:发布Embarcadero RAD Studio 2011版,官方名称为RAD Studio XE
1.3 第一个程序
开发一个应用程序一般要经过以下几个阶段:
✧需求分析与总体设计。此阶段的任务是让程序开发人员充分理解系统的需求和任务,给出实现这些需求与任务的总体方案。
✧代码开发与程序调试。此阶段按照设计方案使用编程语言开发出应用程序。在开发的过程中反复调试以修改语法错误和逻辑错误,最终生成符合要求的可执行文件。
✧投入运行与程序维护。经测试无误的应用程序就可以投入运行了。程序的维护是为了保证程序能正确地运行。
在代码开发与程序调试阶段,使用Delphi时一般包括3个步骤:
程序窗体设计: 包括对窗体中组件的设计。
程序代码设计: 设计窗体和窗体中组件的各种操作和响应事件的处理代码。
编译和调试程序:对程序代码进行编译,修改各种语法错误和逻辑错误,生成正确的可执行代码。
第2章 Delphi语言基础
2.1 编程风格
2.1.1 注释
块注释:通常被用在版权注释中,也被用来注释掉一些代码行。
{ 注释 }
(* 注释 *)
单行注释:作用域只是它所在的一行,使用方便。
//
2.1.2 命名
命名对象可以是常量、变量、函数、过程等用户自已书写的定义的标识。在Object Pascalj里不分大小写。
命名原则:用意思明确的英文单词或者词组命名,且首个字母大写,若是多个单词(不能在单词间插入空格),采用驼峰格式。
例: jklasdf //没有意义
Mylongidentifier //可读性差
Thisismuchmorereadableroutinename //可读性差
MyLongIdentifier
ThisIsMuchMoreReadableRoutineName
注意:命名的第一个字母尽量不要用T,F,I这三个字母。
2.1.3 空白
源代码中的空格、空行及制表符等称为空白区。使用空白可提高程序的可读性,又不影响编译。
2.1.4 缩进
使程序便于阅读理解。不要在源代码中保留Tab字符。
2.2 基本概念
2.2.1 进制
二进制,十进制,十六进制(加$符号)
2.2.2 保留字
程序如同一篇文章,由字符组成单词,再由单词和符号构成句子——语句。其中有一类单词,它们具有特定的语法含义,称为保留字(reserved words)。程序员不得重新定义保留字的语义。常用的保留字如:begin、end、if、then、for、do等。
教材第24页表2-1。
2.2.3 标识符
标识符用作常量、变量、数据类型、属性、过程、函数、单元及程序等的名称。由一个或多个字符序列组成,其构词规则如下:
(1)标识符由字母、数字或下划线组成;
(2)标识符的第一个字符必须是字母或下划线;
(3)标识符的长度不应超过255个字符,否则只有前255个字符有效;
(4)不能将保留字用作标识符;
(5)标识符不区分大、小写。
例如:x、x1、max、a15、Button_OK都是合法的标识符,而5x、x-y、α、ax10.5等都是非法的标识符。
标准标识符:在Object Pascal语言中,有一类标识符是系统预先定义的,它们用于标识系统预先定义的标准函数、标准过程、标准类型、标准常量及标准文件等。
标准常量,如False、True等。
标准类型,如Boolean、Char、String、TDateTime等。
标准函数,如Abs、Eof、ShowMessage、Sqrt等。
标准过程,如Dispose、New、Read、Readln、Reset等。
标准文件,如Input、Output等。
注意:
当程序中自定义的标识符与其引用的单元中所定义的重名时,如果要访问被引用单元的标识符,则必须指示为外部单元的标识符,不然访问的是本程序定义的标识符。
2.3 常量与变量
二者都是存储数据的载体,不同的是常量中的值不能改变,变量中的值则随着程序的运行而改变。一般位于函数或者过程的起始位置定义。
2.3.1 变量
变量是程序设计最基本的要素,是实现人与计算机交流的最基本的媒介,变量中可以存放字符、数值、日期或对象等。
1. 变量的声明
变量说明的一般形式为:
var
<变量标识符列表>: <类型标识符>;
其中,变量标识符列表中可以包含一个或多个变量标识符,若有多个变量标识符时,相邻的两个变量标识符之间应使用逗号“,”隔开;类型标识符用以指定这些变量的数据类型。
变量说明以保留字var开头。一个变量说明部分可包含多个变量的说明,每个变量说明末尾均有分号。一个变量在某一个时刻有且仅有一个值。
2. 变量的命名和格式
与标识符类似
3. 局部变量和全局变量
从作用范围来划分:局部变量和全局变量,在过程或函数内部声明的变量称为局部变量,否则称之为全局变量。
局部变量在它所在的过程或函数执行完后由系统自动释放,全局变量在程序被关闭时释放。在声明变量时,局部变量不能初始化,全局变量可以初始化,但在声明多个同类型变量时不能初始化。
2.3.2 常量
1. 字面常量
(1)整型常量
即整数,如3、10000、-90。在Object Pascal中十六进制形式表示整型常量以字符$开头,如$20相当于十进制的32。
(2)实型常量
即实数,例如,6.6、0.77e+4。后者的表示方法称为指数记数法或科学记数法,0.77e+4表示0.77×104。
Pascal语言中的实数表示和日常书写的形式基本相似,但要注意以下几点:
①小数点前后一定要有数字。
②数中不允许包含空格字符与逗号。例如1,000,000是不合语法的。
③没有分式表示。
④使用指数记数法时,e前面应有整数或实数,e后面必须是整数。
例如:88.0、-0.8、1e+23、-3.45e-6都是正确的实数表示法,而88.、.66、4.4e5.5、e6则是不正确的。
(3)布尔常量
它是指False和True这两个值,False表示逻辑值“假”,True表示逻辑值“真”。
(4)字符常量
字符常量有两种表示方式:
①用单引号对括起来的单个字符,如'a'、'*'、'2'等。
②用#引导一个整数,整数表示该字符的ASCII码。例如,#13、#$20、#$30、#65分别表示回车符、空格符、数字符号'0'、字母'A'。
(5)字符串常量
字符串常量是用单引号对括起来的一串字符,例如,'Good idea'、'96.5'、'#='。
当字符串内有单引号时,要用两个连续单引号表示,例如,'Most children''s English Course'。
书写字符串需要注意以下几点:
①空格字符可以是字符串的组成部分。所以在字符串中的任何空格字符都是其值的一部分;
②字符串中的字母有大小写区分,即'A1'不等于'a1'。
2. 符号常量
字面常量可以在程序中直接使用,而由标识符表示的符号常量需预先定义。
常量定义的一般形式为:
const
<常量标识符> =表达式;
或
<标识符>:<类型标识符>=表达式;
在Pascal程序的声明部分,以保留字const后开始常量声明;“=”号左边为常量标识符;“=”号右边的表达式可以由常量、部分在程序编译时可计算的函数,及先定义的常量标识符等构成,表示符号常量的值。一个类型常量定义部分可包含多个类型常量定义,每个类型常量定义末尾均有分号。
例:const
Pi: Double=3.1415926;
Max=100;
Object Pascal对常量定义有如下要求:
①必须遵循先定义后使用的原则,即只有已定义的常量标识符才能在程序中使用。
②不能改变符号常量的值。
可用于常量定义的函数,即在程序编译时可计算的函数,有Abs、Chr、Length、Odd、Ord、Pred、Round、SizeOf、Succ、Swap、Trunc等(见下表2-2)。使用常量定义的意义在于减少常量值差错机会与修改程序的工作量,并提高程序的可读性。
表2-2 可以在常量表达式中引用的标准函数
函数 | 说明 |
Abs(X) | 求X的绝对值 |
Addr(X) | 返回X的地址 |
Chr(X) | 返回值为X的字符 |
Length(X) | 求字符串X的长度 |
Odd(X) | 判断X是否为奇数 |
Ord(X) | 返回序数类型变量X的序数值 |
Pred(X) | 返回序数类型变量X的前一个值 |
Succ(X) | 返回序数类型变量X的后续值 |
SizeOf(X) | 返回X在内存中占用的字节数 |
Round(X) | 把X四舍五入取整 |
Swap(X) | 交换16位整数的高位和低位 |
Trunc(X) | 把实数X截断为整数 |
Object Pascal所支持的运算符主要有算术运算符、逻辑运算符、关系运算符3大类。
2.4.1 赋值运算符
赋值运算符“:=”是先计算赋值运算符右边表达式的值,再将结果赋给左边的变量。
2.4.2 算术运算符
用于完成算术运算。
对于+、-、*,若参加算术运算的两个数都是整型数据,则运算结果也是整型。
运算符 | 作用 | 操作数类型 | 结果类型 |
+ | 表示正值 | Integer或Real | Integer或Real |
算术加 | Integer或Real | Integer或Real | |
- | 表示负值 | Integer或Real | Integer或Real |
算术减 | Integer或Real | Integer或Real | |
* | 算术的乘运算 | Integer或Real | Integer或Real |
/ | 浮点数的除运算 | Integer或Real | Real |
Div | 整型数的除运算 | Integer | Integer |
Mod | 模运算 | Integer | Integer |
操作数及结果都是布尔值。
运算符 | 作用 | 操作数类型 | 结果类型 |
not | 逻辑非 | Boolean | Boolean |
and | 逻辑与 | Boolean | Boolean |
or | 逻辑或 | Boolean | Boolean |
xor | 逻辑异或 | Boolean | Boolean |
对操作数进行位级操作。部分位运算符与逻辑运算符在形式上是一样的,区别是其操作数及返回结果。
运算符 | 作用 | 操作数类型 | 结果类型 |
Not | 按位非 | Integer | Integer |
And | 按位与 | Integer | Integer |
Or | 按位或 | Integer | Integer |
Xor | 按位异或 | Integer | Integer |
Shl | 按位左移 | Integer | Integer |
Shr | 按位右移 | Integer | Integer |
E1 Shr E2:E1除以2的E2次方的整数部分,
2.4.5 关系运算符
用于比较两个量的值。结果为布尔值。
运算符 | 作用 | 结果类型 |
= | 等于 | Boolean |
<> | 不等于 | Boolean |
< | 小于 | Boolean |
> | 大于 | Boolean |
<= | 小于或等于 | Boolean |
>= | 大于或等于 | Boolean |
In | 属于 | Boolean |
例:X=Y运算应当写成Abs(X-Y)<1e-6;而X<>Y运算应写成Abs(X-Y)>1e-6。
2.4.6运算符优先级
复杂表达式中的同一括号层内,各运算的先后次序取决于运算符的优先级。
按照操作数的个数可以将运算符分为两类:单目运算符和双目运算符。只有^、@和not是单目运算符,其他的为双目运算符。其中,+和-既可作为单目运算符(正数、负数)又可作为双目运算符(加、减)。单目运算符只能放在操作数的前面,双目运算符都放在两操作数的中间。对于可变类型的数据操作,大多数操作符都可以对其进行操作,只有^、is和in例外。
确定优先级的3条基本原则:
●两个运算符之间的操作数总是首先参加高优级的运算,
●两个相等优先级运算符之间的操作数按从左到右的顺序参加运算,
●括号里面的表达式总是优先于单个运算符的运算。
例: total:=10+15*2 div (4+2 xor 3)
习题
1.简述Object Pascal中标识符的命名应遵循哪些规则。
2. Object Pascal中提供了哪些类型运算符,在表达式中其优先级从高到低如何排列。
3.注释语句有哪几种形式?
4.什么是变量的作用域?根据变量的作用域,可将变量分为哪几类。
第3章 Object Pascal中的数据类型
3.1 基本数据类型
基本数据类型分为:有序类型、浮点类型、时间日期类型、字符串类型。
3.1.1 有序类型
有序类型包括整型、字符型、布尔型、枚举型和子界型。
有序类型是一种线性的数据结构,每个值都有唯一的前驱(除第一个)和唯一的后继(除最后一个)。每个数都有一个确定的序号,对整数而言该序号就是其本身,而对其他的有序类型(子界类型除外),黙认情况下,第一个值的序号为0,第二个为1,依次类推。
用于处理有序类型的表达式或变量的常用函数
函数 | 参 数 | 返 回 值 | 备 注 |
Ord | 有序类型变量或有序类型表达式 | 有序类型表达式的序号 | 不能带Int类型的参数 |
Pred | 有序类型变量或有序类型表达式 | 有序类型表达式的先行数 | 不能在拥有write过程的属性上使用 |
Succ | 有序类型变量或有序类型表达式 | 有序类型表达式的后继数 | 不能在拥有write过程的属性上使用 |
High | 有序类型变量或有序类型表达式 | 有序类型中序数最大的值 | 可以用于shorstring类型或数组 |
Low | 有序类型变量或有序类型表达式 | 有序类型中序数最小的值 | 可以用于shorstring类型或数组 |
类型 | 取值范围 | 存储格式 |
Integer | -21474838~21474837 | 有符号32位整数 |
Cardinal | 0~4294967295 | 无符号32位整数 |
Shortint | -128~127 | 有符号8位整数 |
Smallint | -32768~32767 | 有符号16位整数 |
Longint | -21474838~21474837 | 有符号32位整数 |
Int | -263~263-l | 有符号位整数 |
Byte | 0~255 | 无符号8位整数 |
Word | 0~65535 | 无符号16位整数 |
Longword | 0~4294967295 | 无符号32位整数 |
字符型的类型标识符是Char。字符型的数据只能是单个字符,不能是一串字符。例如‘ABC’,‘x=?’ 等都不是字符型的数据,而是字符串。
字符类型 | 占用字节数 | 存储内容 |
AnsiChar | 1 | 存储一个Ansi字符,基本类型 |
WideChar | 2 | 存储一个Unicode字符,基本类型 |
Char | 1 | 同AnsiChar,Delphi将来的版本可能对应于WideChar,通用类型 |
常用的处理字符的函数:
●Chr(x:Byte):Char 该函数返回ASCII中某序数所代表的字符。它与Ord函数互为逆函数。
●UpCase(Ch:Char) 该函数将小写字母转换为大写字母,当其参数不是小写字母时,该函数则会返回原来的字符。
3. 布尔类型
布尔类型 | 占用字节数 | 存储内容 |
Boolean | 1 | 通用类型 |
ByteBool | 1 | 基本类型 |
WordBool | 2 | 基本类型 |
LongBool | 4 | 基本类型 |
布尔类型特性比较
Boolean | ByteBool、WordBool、LongBool |
FalseFalse<>True | |
Ord(False)=0 | Ord(False)=0 |
Ord(True)=1 | Ord(True)<>0 |
Succ(False)=True | Succ(False)=True |
Succ(True)=True | Succ(True)=False |
Pred(True)=False | Pred(False)=True |
Pred(False)=True | Pred(True)=True |
枚举类型是用户自定义一组具有特定意义的值,即用一些标识符来表示一系列有序数。但是数目不能超过255。定义枚举类型的语法如下:
type
typeName=(val1,...,valn)
其中type是定义枚举类型的关键字,typeName是枚举类型名称,val1,...,valn是用户自己定义的一组有意义的标识符,它们不能和已有保留字或者与它们同一模块的某些标志符相同
例:
type
TSuit=(Club,Diamond,Heart,Spade);
TOrientation=(North,South,East,West);
枚举类型可以提取的每个值都对应于一个整数值。黙认情况下每个值都会根据定义的顺序(从0开始),向右依次增加1,也可以通过=重新定义每个枚举项的实际值。
比如:
type
TSuit=(Club=1,Diamond=3,Heart=5,Spade=Club+Heart);
此外,还可以只对一部分枚举项赋值:
type
TSuit=(Club=1,Diamond=3,Heart,Spade);
没有被赋值的枚举项会自动获得一个初始值,其规则是:最后一个明确赋值的枚举项的序列值加上1。
注意:
●同一个枚举项不能出现在多个枚举类型中。如:
type
TSuit=(Club,Diamond,Heart,Spade);
TBody=(Chest,Heart,Arm,Eye,Hand);
●不能直接用枚举类型中的元素进行运算操作。
例:
type
TSuit=(Club,Diamond,Heart,Spade);
var
suit1,suit2,suit3:TSuit;
begin
suit1:=heart;
suit2:=suit1;
suit3:=Club+Heart; //错误
end;
●枚举值的输出常用case语句间接地输出
●枚举类型是有序数据类型,对其运算可以使用函数Ord、Succ、Pred及关系运算。
5. 子界类型
子界类型指的是某个有序类型(称为基类)的一个子集。定义子界类型的语法是:
type
typeName=Low..High;
其中typeName是子界类型名,Low是子界类型的下界,High是子界类型的上界,Low与High必须是同一种顺序类型,且Low<=High。
例:
type
SomeThing1=1..10;
SomeThing2=’a’ ..’z’;
TDay=(Sunday,Monday,Tuesday,Thursday,Friday,Saturday);
TWorkDay=Monday..Friday;
注意:
●子界类型的上下界常数必须是同一类型,且必须是有序类型
●子界类型变量具有基类型数据的所有运算特性,但运算结果必须在所定义的上下界范围之内
●一个子界类型继承它的常量类型的运算符和标准函数,常量类型相容的不同子界类型可以混合运算,可以赋值
●子界类型的下上界必须是依次有序递增的
3.1.2 浮点类型
浮点类型是全体带符号的实数的统称,它的值域几乎是无限的,它参与的运算几乎都是近似计算。Object Pascal语言中用Real标识通用实型。浮点类型有以下几种基本类型:
类型 | 范围 | 有效位 | 所占字节数 |
Double | 5.0*10-324~1.7*10308 | 15~16 | 8 |
Real48 | 2.9*10-39~1.7*1038 | 11~12 | 6 |
Single | 1.510-45~3.4*1038 | 7~8 | 4 |
Extended | 7.4*10-4932~1.1*104932 | 19~20 | 10 |
Comp | -263+l~263-l | 19~20 | 8 |
Currency | -922337203685477.5808~922337203685477.5807 | 19~20 | 8 |
系统提供的标准函数:
(1)绝对值函数Abs(x):函数值为x的绝对值。
(2)平方函数Sqr(x):函数值为x的平方。
(3)正弦函数Sin(x):函数值为x的正弦,其中x的单位为弧度。
(4)余弦函数Cos(x):函数值为x的余弦,其中x的单位为弧度。
(5)反正切函数Arctan(x):函数值为x的反正切,函数值的单位为弧度。
(6)指数函数Exp(x):函数值为指数ex。
(7)对数函数In(x):函数值为x的自然对数。
(8)平方根函数Sqrt(x):函数值为x的平方根。
(9)舍入函数Round(x):对实数x作四舍五入,结果为整数。例如:Round(5.6)的值为6,Round(-7.6) 的值为-8。
(10)截尾取整函数Trunc(x):截去实数x的小数部分,结果为整数。例如:Trunc(-9.9)的值为-9,Trunc(7.8) 的值为7。
(11)取整函数Int(x):截去实数x的小数部分,返回整数部分,结果为实型。
(12)取小数函数Frac(x):返回实数x的小数部分,结果为实型。
3.1.3 时间日期类型
日期时间型TDateTime在Object Pascal中实际是双精度浮点型(Double);其原型是:
Type TDateTime =type Double;
TDate =type TDateTime;
TTime =type TDateTime;
Object Pascal中规定:以19年12月30日00:00时为准计为0,每增加1天,日期时间类型数据增1,每增加1小时,日期时间类型数据增1/24,每增加1分钟,日期时间类型数据增1/(24*60)……依次类推。因此,整数部分表示距离该日该时的天数。例:
19年12月30日 00:00 0
1900年1月1日 18:00 2.75
2005年9月14日 12:00 38609.5
2009年9月14日 15:00 40070.625
日期型数据的运算:
◆D + N、或D – N
计算某个日期之前或之后若干时间的日期。其中,D是日期时间型的数据,N是实数。表达式的值为日期时间型数据。
◆D1-D2
计算两个日期时间的时间间隔。其中D1、D2为日期时间型数据,结果为实型数据。结果为负数则表示D1时间在D2时间之前,否则相反。
标准函数和过程
(1)Date():函数返回系统当前日期,无参数,返回数据是TDateTime型。
(2)Time():函数返回系统当前时间,无参数,返回数据是TDateTime型。
(3)Now():函数返回系统当前日期和时间,无参数,返回数据是TDateTime型。
(4)StrToDate('日期字符串') :字符串转换为日期时间函数,返回数据是TDateTime型;
StrToTime('时间字符串'):参数为时间串,返回数据是TDateTime型;
StrToDateTime('日期时间型串'):参数为日期时间串,返回数据是TDateTime型。如:
StrToDate('10/1/2004');
StrToTime('12:50:24');
StrToDateTime('10/1/2004 12:00:00');
(5)取日期时间中的部分数据,以下函数的参数均为日期时间型:
Dateof(参数):返回去掉时间后的日期(TDateTime型);
Timeof(参数):返回去掉日期后的时间(TDateTime型);
Yearof(参数):返回日期的年份(Word型);
Monthof(参数):返回日期的月份(Word型);
Dayof(参数):返回日期的日号(Word型);
Weekof(参数):返回日期在该年份是第几个星期,返回1到53之间的整数。
(6)日期时间转换为字符串的函数,返回值为字符串,如:
TimeToStr(参数):将时间数据转换为字符串返回;
DateToStr(参数):将日期数据转换为字符串返回;
DateTimeTostr(参数) :将日期时间数据转换为字符串返回。
此外,还有Hourof、Minuteof、Secondof、FormatDateTime、DecodeDate、DecodeTime、EncodeDate、EncodeTime等。
3.1.4 字符串类型
1. 字符串类型
是用一对单引号括起来的一系列字符。
字符串类型的表示范围和存储格式
类型 | 最大字符数 | 字节数 | 是否以Null结尾 |
ShortString | 255 | 2~256B | 否 |
AnsiString | 约231 | 4B~2GB | 是 |
WideString | 约230 | 4B~2GB | 是 |
例如,s=’Delphi7’,s[0]为7,s[1]为’D’,
●AnsiString,长字符类型,长度几乎是无限的,在声明后自动被初始化为空字符串,索引从1开始,在它最后一个字符后自动加一个NULL字符表示字符串结束。
以NULL结束的字符串主要用于跟Windows的API或其他语言的例程兼容,如:
Var
Caption,Message:AnsiString;
begin
Caption:=’Hello World’;
Message:=’我昨天看到你笑了^_^’;
MessageBox(0,Pchar(Message),Pchar(Caption),MB_OK);
end;
●WideString,长字符类型,在Delphi3以后引入,主要用OLE编程。
字符串的通用类型是String,黙认与AnsiString等同。
编译开关 String等同于
{$H-} ShorString
{$H+} AnsiString
在Delphi的源程序代码中,可以设置一些编译指令,用于指示编译器程序代码的生成方式、中间文件、编译路径等。其一般形式如下:
{$编译指令 参数}
即,在“{”或“(*”符号之后紧跟符号“$”,则开始编译指令的声明。例如,{$R *.DFM}指示窗体文件是与单元文件同名的DFM文件;又如,{$WARNINGS OFF}告诉编译器在编译期间不产生警告信息。
常规的编译指令也可以通过选择执行Delphi IDE的【Project】→【Options…】菜单项,在打开的“Project Options”对话框中的“Compile”页上进行设置。
2. 常用字符串函数
procedure SetLength(var S;NewLength:Integer);
function Pos(Substr:string; S:string):Integer;
function Copy(S; Index, Count: Integer): string;
procedure Insert(Source: string; var S: string; Index: Integer);
procedure Delete(var S: string; Index, Count:Integer);
function Trim(const S: string): string;
3.2 复杂数据类型
3.2.1 记录类型
记录类型描述一组不同类型的数据元素集合,每个数据元素称为“域”。在定义一个记录类型时,需要指定每个数据域的数据类型。定义记录类型的语法如下:
type
记录类型标识符 = record
域1: 类型1;
域2: 类型2;
.…..
域n: 类型n;
end;
例如:type TPerson = record
name : String[10];
id : String[15];
sex : Boolean;
age : Byte;
height, weight : Real;
end;
声明记录类型变量的形式为:
var
记录变量:记录类型标识符;
例如:
var
man1: Tperson;
访问记录域,可以使用“变量名.域名”的形式,如man1.name,man1.sex,man1.age等,也可以使用with语句:
with 记录变量名 do
begin
……
……
end;
3.2.2 集合类型
集合类型是一组相同类型元素的组合。引入集合的目的是为了把一组相关的对象作为一个整体参加运算,其中每一个对象称为集合的元素。集合类型通常用于检查一个值是否属于一个特定的集合,也常用于维护一系列互不相同的处理对象。
1. 声明集合类型
type
集合标识符=set of 基类型
Object Pascal中规定了基类型只能是不超过256个有序值的集合,集合的元素的序数值必须介于0和255之间,且基类型的值域的上界必须大于或等于下界。例如:
type
TSetA = set of Integer; // 错误
TSetB = set of 255..300; // 错误
TSetC = set of WideChar; // 错误
TsetD = set of 10..50; // 正确
TsetE= set of char; // 正确
2. 集合类型常量变量
集合变量的赋值用方括号表示。
type
TAges=set of 0..100;
TUpCaseChars=set of ‘A’..’Z’;
var
MyAge:TAges;
MyUpCaseChars:TUpCaseChars;
begin
MyAge:=[11,22,33,44,55];
MyUpCaseChars:=[‘C’,’H’,’I’,’N’,’A’];
end;
常量的定义与变量的定义相似:
const
MyAge=[11,22,33,44,55];
MyUpCaseChars=[‘C’,’H’,’I’,’N’,’A’];
3. 集合的运算
关系运算
集合类型的关系运算返回结果为布尔值。
(1)运算符=、<>判断两个集合相同或不相同。如:表达式 [1, 3, 5] = [3, 1, 5] 的值为True;
(2)>= (包含)、<= (包含于)。
如:表达式 [1,3] >= [3] 的值为True;
(3)属于运算in,如:表达式 3 in [3,5] 的值为True。
增删运算
增删运算用+、-运算符或Include()和Exclude()来实现。
procedure Include(var S: set of T; I:T);
procedure Exclude(var S: set of T;I:T);
3.2.3 指针类型
指针类型的变量存储的是内存地址,利用指针可以灵活地访问内存中的数据。
1. 定义指针类型
指针类型的声明格式如下:
type
指针类型标识符 = ^基类型;
例:type
Pbyte=^Byte;
PwideChar=^WideChar;
Pstu=^Student;
Student=record
Name:string;
Age :Integer;
Sex :(Male,Female);
End;
指针可以指向任何数据类型。System和SysUtils单元声明了许多常用的标准指针。
2. 操作指针类型
指针类型的运算符
运算符 | 作用 | 操作数类型 | 结果类型 |
+ | 将指针指向的地址增加一个偏移量 | Integer,Pointer | Pointer |
- | 将指针指向的地址减少一个偏移量 | Integer,Pointer | Pointer,Integer |
^ | 取指针指向地址的内容 | Pointer | 指针的基类型 |
= | 判断两个指针是否指向同一个地址 | Pointer | Boolean |
<> | 判断两个指针是否指向不同的地址 | Pointer | Boolean |
New过程用于在应用程序的堆栈中为动态变量分配一块区域,并把该区域的地址赋值给指针变量P,所分配区域的大小由指针所指向的类型决定。
procedure Dispose(var P: Pointer);
Dispose过程用来释放为变量分配的内存空间。Dispose常和New配对使用,当分配的动态存储空间不再使用时,应及时地释放所分配的存储空间,避免发生错误。
例:
Var
p:^Integer;
begin
New(P);
P^:=20;
ShowMessage(IntToStr(p^));
Dispose(p);
end;
procedure GetMem(var P: Pointer; Size: Integer);
function AllocMem(Size: Cardinal): Pointer;
function Addr(X): Pointer;
例:
Var
x,y:integer;
p:^integer;
begin
x:=88;
p:=Addr(x); // p:=@x;
y:=p^;
end;
3. 无类型指针
无类型指针是指指针变量声明时没有给出基类型的指针类型,无类型的指针是这样声明的:
var
p:pointer;
无类型指针可以指向任何类型,但不能直接用类似P^的形式来引用它的动态变量,需要预先类型转换为另一个有类型指针变量。如:
Type
PInteger=^Integer;
var
S:Single;
I:Integer;
P:Pointer;
PI:PInteger;
begin
//…
P:=@S;
PI:=PInteger(P);
I:=PI^;
end;
4. 特殊的指针PChar
这是一个指向以Null字符结尾的字符串的指针,主要用于与外部函数兼容。
例子:
var
s:ShortString;
p:Pchar;
begin
s:=’New’;
s:=s+char(0);
// p:=@s[1];
p:=@s;
p:=p+1;
ShowMessage(StrPas(p));
end;
PChar和PwideChar中指针可以使用的运算符
运算符 | 作用 | 针对类型 | 返回值 |
+ | 指针相加 | 字符指针 | 整数类型 |
- | 指针相减 | 字符指针 | 整数类型 |
= | 指针相等 | 所有指针 | 布尔类型 |
<> | 指针不等 | 所有指针 | 布尔类型 |
变体类型(Variant)是指可以在程序运行期间确定或改变的数据类型。这些数据在编译期间不能确定其数据类型,而且,它们比固定类型的数据占用更多的存储空间和更多的操作时间。
默认的情况下,变体类型可以是除了记录类型、集合类型、静态数组类型、文件类型、类类型和指针类型之外的任何类型,也就是说,变体类型可以是除了结构类型和指针类型之外的任何其他类型。
例如有如下变量声明:
var
v:Variant;
i:Integer;
str:String;
则,以下变量的使用是合法的:
i: =10 ;
v := i;
v:=str;
3.3 数 组
数组类型数据表示的是同种类型数据的集合。数组类型的数据是排列有序的,每个数据元素都有一个唯一的索引号。与集合类型不同的是,数组类型的数据可以重复,元素的数据类型可以是简单类型,也可以是自定义类型。数组类型按照内存分配方式可以分为静态数组和动态数组。
1. 静态数组:在声明时指定了数组的大小。
定义静态数组的语法形式如下:
type
ArrayName=array [indexType1, ..., indexTypen] of baseType;
其中,ArrayName 是数组标识符,indexType是有序类型,通常是以Integer为子界的,也可以是其它有序类型的子界;baseType声明元素的数据类型;数组由同一类型的数据元素组成。
例:
type
AX=(a,b,c,d);
MyArray=array[AX] of Integer;
TNumber=array[‘a’..’z’] of Integer;
TArr1 = Array[1..10] of Real;
TArr2 = Array[1..3,1..5] of Char;
var
ax1:MyArray; // 声明变量ax1是MyArray类型数组
num:TNumber; // 声明变量num是TNumber类型数组
ar1:Tarr1; // 声明变量ar1是Tarr1类型数组
ar2:Tarr2; // 声明变量ar2是Tarr2类型数组
也可以在声明变量时直接定义数组的类型,如:
var
a: Array [1..10] of Integer;
数组元素的访问是通过数组名后面加上方括号和下标值来访问的。如:a[1]:=10;
方括号内的下标值必须符合数组类型中下标类型的定义,其类型必须与下标类型一致,可以是表达式,但其值必须在下标取值的范围内。如:a[2+6]:=100;
注意:Object Pascal的下标不是必须从0或1开始,在for循环中使用数组时一定要小心。可以在循环中使用函数High(),Low()使程序更加稳定,更易于维护。
2. 动态数组:在定义时并没有确定数组的大小或长度,而是在访问之前用SetLength过程为数组动态或重新分配其存储空间。
定义动态数组的语法形式如下:
Var
VariableName: array of baseType;
例如:
var DynArr: array of Integer;
声明DynArr为元素是整型的动态数组。
也可以先定义类型,再声明变量,如:
type TdynIntArr = array of integer;
var DynArr:TdynIntArr;
语句SetLength(DynIntArr,10); 为动态数组DynIntArr分配10个元素的存储空间,下标从0到9,动态数组的下标总是整数类型,并且总是从0开始。如要释放动态数组占用的存储空间,可以将nil赋值给该动态数组变量,或调用过程SetLength(DyIntArr,0)实现。
动态数组通过使用嵌套的“array of ...”结构实现,例如:
type
TGrid = array of array of String; // 定义二维动态字符串数组类型Tgrid
动态数组是生存期自管理的,在用完它们后没有必要释放。若需要删除动态数组以释放它使用的内存空间,仅需要把nil赋值给动态数组:
A1:=nil;
假设A1与A2都属于相同的动态数组类型的变量,则可以进行下面的语句:
A1:=A2;
将数组A1分配与A2同样长度,同时把A1指向与A2一样的数组。动态数组的赋值其实是传递地址。如:
var
A1,A2:array of Integer;
begin
Selength(A1,4);
A2:=A1;
A1[0]:=23;
A2[0]:=100;
ShowMessage(IntToStr(A1[0])); //100
end;
如果想把A1的值赋值给A2,可以用标准过程Copy:
A2:=Copy(A1);
这时A1和A2是两个的数组,另外还可以用:
A2:=Copy(A1,1,2); //从元素1开始,复制2个元素