第2章 Object Pascal语言基础

来源:互联网 发布:slack windows 编辑:程序博客网 时间:2024/05/20 18:54

本章重点

l         保留字和标识符

l         常量与变量

l         数据类型

l         运算符与表达式

l         语句

l         过程与函数

 

Delphi的编程语言是Object Pascal,即面向对象的Pascal语言。自Delphi 7 开始,Object Pascal语言改称为 Delphi 语言。

第1节保留字和标识符

一、保留字

保留字是由系统使用的具有特殊含义的单词(如And、If、For、Var等),详见教材16~17页表2.1。

二、指令符

指令符也是由系统使用的具有特殊含义的单词(如Public、Private等),详见教材17页表2.2。

三、标识符

标识符(Identifiers)用于表示常量、变量、域(字段)、类型、属性、过程、函数、程序、单元、库和包(packages)的名称

Object Pascal标识符的声明和使用应遵循以下规定:

·        长度任意,但仅前255个字符有效。

·        首字符必须是字母或下划线。

·        不能含有空格,中间的字符可以是字母、数字和下划线。

·        不能使用保留字(reserved words)作为标识符。

·        不区分大小写,例如sName与sname等价。

第2节注释

三种注释形式:

{ 注释内容 }

(* 注释内容 *)

// 注释内容

注意

如果注释符{之后紧跟一个美元符号$(如{$R *.res}),表示该语句是一条编译指令,它与普通的注释不同,通常由Delphi自动生成,用于设置编译过程,不要修改或删除它。

第3节常量和变量

一、常量

1. 普通常量

如:123,-100,3.14,'abc',True等。

2. 符号常量

符号常量用保留字Const声明,格式如下:

Const 常量名 = 表达式;

例如:

Const

  PI = 3.1415926535897932385;

  College = '山东教育学院';

  Numeric = ['0'..'9'];     // 数字字符集合

  Alpha = ['A'..'Z', 'a'..'z'];  // 英语字母集合

  AlphaNum = Alpha + Numeric;    // 集合的并

2. 变量

变量声明的格式:

var 变量名表 :类型;

例如:

var

  X, Y, Z: Double;

  I, J, K: Integer;

  S1, S2: String;

  Digit: 0..9; // 子界类型

  Flag: Boolean;

单元级或全局变量可以在声明时初始化(每个声明语句仅限一个变量)。例如:

var

  x: Integer = 0;

  S: string = 'abc';

第4节数据类型

本节要点

l         简单类型

l         字符串类型

l         类型相容与类型映射

l         掌握集合类型的声明和应用

l         掌握数组类型的声明

l         了解记录类型

 

概述

1. 数据类型分类

Object Pascal的数据类型可分为以下几类:

·        简单类型:包括有序类型(型、字符型、布尔型、枚举型和子界型)和实数类型。

·        字符串类型

·        结构类型:包括集合数组记录文件类引用接口类型。

·        指针类型

·        过程类型

·        可变类型

2. 预定义类型与自定义类型

有些数据类型是在Object Pascal中预先定义好的,编译器能够自动识别,无须编程者定义即可直接使用(如整型、实型、字符型、字符串型等)。这些数据类型属于预定义类型(predefined types),或称内置类型(built-in types)。

另外一些数据类型在使用前必须由编程者定义(如枚举、子界、结构类型等),这些数据类型属于自定义类型(user-defined types)。自定义类型需用type保留字声明:

type 自定义类型名称 = 类型;

一、简单类型(Simple)

包括有序类型和实数类型。

特点:一个简单类型的变量只存储单一值,它占用的内存大小相对固定。

1. 有序类型

有序类型(Ordinal types)包括整数、字符、布尔、枚举和子界类型。有序类型定义一组有序的值,其中除第一个值以外均有一个惟一的前接值(predecessor),除最后一个值以外均有一个惟一的后继值(successor)。每个值都有一个序号,在多数情况下,若某值的序号为n,则其前接值的序号为n-1,后继值的序号为n+1。

整数类型值的序号是其本身;子界类型保留其基类型的序号;其他类型中第一个值的默认序号为0,后续值序号依次加1。枚举类型的声明可以覆盖默认值。

以下是操作有序类型的常用预定义函数:

函数

参数

返回值

Ord

有序表达式

表达式值的序号

Pred

有序表达式

表达式值的前接值

Succ

有序表达式

表达式值的后继值

High

有序类型标识符或变量

类型中的最高值

Low

有序类型标识符或变量

类型中的最低值

High和Low亦可用于短缩字符串类型和数组。

例如:Byte 类型的最高值为255,因此,High(Byte)返回255。2的后继值是3,因此Succ(2)返回3。

标准过程IncDec分别使有序变量的值加1和减1。例如,Inc(I) 与 I := Succ(I) 等价;若I为整型变量,则Inc(I)相当于I := I + 1。

(1)整数类型

·        通用整型:

类型

数值范围

格式

Integer

-2147483648..2147483647

有符号 32-bit

Cardinal

0..4294967295

无符号 32-bit

 

·        基本整型:

类型

数值范围

格式

Shortint

-128..127

有符号 8-bit

Smallint

-32768..32767

有符号 16-bit

Longint

-2147483648..2147483647

有符号 32-bit

Int64

-263..263-1

有符号 64-bit

Byte

0..255

无符号 8-bit

Word

0..65535

无符号 16-bit

Longword

0..4294967295

无符号 32-bit

(2)字符类型

类型

占用字节数

存储内容

Char

1

存储一个ANSI字符

AnsiChar

1

存储一个ANSI字符

WieChar

2

存储一个Unicode字符

Char为通用类型。

常用函数:

Chr函数:Chr(65)返回'A',与#65等价。

#”常用于生成控制字符。例如,下面的表达式表示在两个字符串之间插入回车换行符:

'字符串1'#13#10'字符串2'

(3)布尔类型

类型

占用字节数

False序号

True序号

Boolean

1

0

1

ByteBool

1

0

非0

WordBool

2

0

非0

LongBool

4

0

非0

 

Boolean为首选类型。

注意:上表后两列中的0、1、非0只是序号,而不是布尔值本身。在Object Pascal中,布尔表达式不能与整数或实数转换。例如,若X是一个整型变量,则以下语句将产生编译错误:

ifX then ...;

可以用以下语句:

ifX <> 0 then ...;   

(4)枚举类型(Enumerated types)

枚举类型是一组有序的标识符。枚举类型没有固定的范围,须由程序员定义。这种需要编程者定义的数据类型称为“自定义类型”。

声明:

type 枚举类型名 = (标识符列表);

例如:

type

TMyColor= (mcRed, mcGreen, mcBlue);

Answer= (ansYes, ansNo);

varColor1, Color2: TMyColor; Ans1: Answer;

(标识符列表)本身起着类型名的作用,因此亦可直接声明变量:

varColor1, Color2: (mcRed, mcGreen, mcBlue);

(5)子界类型(Subrange types)

子界类型是某一有序类型值的子集。子界类型属于自定义类型。

基类型(base type):在子界、集合、数组、指针等自定义类型声明中引用的数据类型。

注意:区分类型(base type)与基本类型(Fundamental type)。

声明:

type 子界类型名 = 下界..上界;

例如:

{ 声明一个枚举类型 }

typeTColors = (Red, Blue, Green, Yellow, Orange, Purple, White, Black);

{ 定义子界类型,它的“基类型”是上面声明的枚举类型TColors }

typeTMyColors = Green..White;

又如:

type

TGrade= 0..100; //基类型是整数类型

TLetter= 'A'..'Z'; //基类型是字符类型

varMyGrade: TGrade; MyLetter: TLetter;

“下界..上界”本身起着类型名的作用,因此可直接声明变量:

varx, y: 1..200;

注意:为子界类型的变量赋值时,不应超出其上下界。

2. 实数类型

类型

数值范围

有效位数

字节

通用

Real

5.0×10-324~1.7×10308

15~16

8

基本

Real48

2.9×10-39~1.7×1038

11~12

6

Single

1.5×10-45~3.4×1038

7~8

4

Double

5.0×10-324~1.7×10308

15~16

8

Extended

3.6×10-4951~1.1×104932

19~20

10

Comp

-263+1~263-1

19~20

8

Currency

-922337203685477.5808~922337203685477.5807

19~20

8

 

3. 日期和时间

在Delphi内部采用实数(Double)存取日期和时间信息。为了便于使用,Delphi在系统单元(System.pas)中定义了TDateTime数据类型(映射为Double)。该类型数据的整数部分代表日期(0=1899年12月30日),小数部分代表时间(时刻÷24),可以分别进行算术运算。

以下是系统定义的常用日期时间函数:

l        Date:返回当前系统日期

l        Time:返回当前系统时间

l        Now:返回当前系统日期和时间

以下函数将日期时间型数据转换为字符串:

function DateTimeToStr(DateTime: TDateTime): string;//日期和时间

function DateToStr(Date: TDateTime): string;//日期

function TimeToStr(Time: TDateTime): string;//时间

以下函数将日期时间格式的字符串转换为日期时间型数据:

function StrToDateTime(const S: string):TDateTime;

function StrToDate(const S: string): TDateTime;

function StrToTime(const S: string):TDateTime;

二、字符串类型

类型

最大长度

存储空间

格式

ShortString

255字符

2~256 B

ANSI 字符

AnsiString

231字符

4 B~2GB

ANSI 字符

WideString

230字符

4 B~2GB

Unicode 字符

 

保留字string默认为AnsiString类型。

例如:

变长字符串:

varS1, S2: string

定长(短)字符串(最大长度255):

varMyString: string[100];

提示

l        标准函数Length可以获取字符串的长度。

l        对字符串中的单个字符可以通过其位置序号存取。例如:S1[1]表示字符串S1中的第1个字符。

l        字符串常量内的两个连续的单引号代表一个被引用的单引号。例如:

'It''sa football.'    {It's a football.}

''''                      {'}

三、结构类型

特点:结构类型(Structured types)的变量可含有多个值,它占用的内存大小不固定。

1. 集合(Set)类型

集合是一组特定同类有序类型(称为基类型)值的元素,这些元素没有内在的顺序。集合中最多可有256个基类型值,每个值的序号必须在0~255之间。

(1)集合类型的声明和应用

声明:

type 集合类型名 = set of 基类型

由于集合类型中元素的个数及其序号受限,因此,通常用子界声明集合类型。例如:

typeTMonth = set of 1..12; // 声明集合类型,基类型为整数类型子界

...

varM1, M2:TMonth;  // 声明集合变量

亦可用set of ... 结构直接声明变量:

varM1: set of 1..12;   // 声明集合变量

...

M1:=[1,3,5,7,8,10,12];  // 为集合变量赋值

以下是set of ... 结构的几个示例:

setof 'a'..'z'

setof Byte

setof (Club, Diamond, Heart, Spade)

setof Char

若需判断某集合中是否有某个成员,用in操作符。例如:

if5 in M1 then ...

(2)集合构造器(Set constructors)

集合构造器代表一组集合类型的值,格式为:

[ 项1, ..., 项n ]

其中每一项既可以是代表基类型中某个值的表达式,也可以是用两个句点(..)隔开的成对表达式。例如:

[5,6, 7, 8]

等价于:

[5..8]

又如:

['A'..'Z','a'..'z', '0'..Chr(9 + 48)]

集合构造器可以为同类型的集合型变量赋值,亦可进行集合运算。

集合类型可以是空集,用一对方括号[]表示。

注意:即使某集合中只有一个元素,也必须使用方括号。

2. 数组(Array)类型

数组由一组具有索引(下标)的同类型元素组成。

(1)一维静态数组
① 声明

type 数组类型名 = array[下标类型] of 基类型

其中,下标类型必须是有序类型,常用整数子界。

例如:

TypeMyArray = array[1..100] of Integer;

...

varArr1: MyArray;

亦可直接声明数组变量:

varArr2: array[1..50] of Integer;

HighLow函数可分别返回数组的上下界。

VarArrayHighBound函数和VarArrayLowBound函数分别返回变体型数组的上下界。

② 数组类型与赋值

数组的赋值相容规则要求相互赋值的数组必须属于同一类型(即类型同一)。Delphi采用数据类型名称等价(name-equivalence)规则,具有类型名作用的语法结构(如“array[1..10] of Integer”)每出现一次均代表不同的数据类型。因此以下代码编译时将无法通过:

var

  Int1: array[1..10] of Integer;

  Int2: array[1..10] of Integer;  //Int1 和 Int2 属于不同类型

  ...

Int1:= Int2;  //出错

可以按以下形式声明数组变量:

varInt1, Int2: array[1..10] of Integer;

或者先声明数组类型标识符,然后用该标识符声明数组变量:

typeIntArray = array[1..10] of Integer;

var

  Int1: IntArray;

  Int2: IntArray;

(2)二维静态数组

声明:

type 数组类型名 = array[下标1, 下标2] of基类型

例如:

typeTMatrix = array[1..10, 1..50] of Real;

(3)动态数组

动态数组的长度不固定

声明:

type 数组类型名 = array  of 基类型

亦可直接声明数组变量:

varMyArr1: array of Integer;

若重复array of可生成多维动态数组。例如,声明一个二维动态数组变量:

varMyArr2: array of array of Integer;

声明动态数组变量后,用SetLength函数设置数组长度。

语法:

SetLength(数组变量,长度);

例如:

{设置一维动态数组MyArr1为10个元素,索引号为0~9}

SetLength(MyArr1,10);

{设置二维动态数组MyArr2的长度,第一维3个元素,第二维4个元素}

SetLength(MyArr2,3, 4);

3. 记录(Record)类型

记录是一组不同类型的元素,每个元素称为一个或字段。声明记录类型时为每个域指定一个名称和类型。

语法:

type 记录类型名 = record   //不加分号

  域名1: 类型1;

  ...

  域名n: 类型n;

end

例如:

typeTStudent = record  //不加分号

  sNo: string[20];

  sName: string[20];

  sSex: string[2];

  sAge: integer;

end;

...

varStud: TStudent;// 声明记录类型变量

对记录类型变量的访问格式:

记录类型变量.域

例如:

Stud.sNo:=‘1001’;

Stud.sName:=‘张三’;

With语句访问:

withStud do

 begin

   sNo:=‘1002’;

   sName:=‘李四’;

   sSex:=‘男’;

   sAge:= 20;

 end

case保留字可以在记录类型内定义可变部分(variant part)

4. 记录类型和动态数组综合示例

见教材34~38页【例2-4】。

5. 指针类型(Pointer)

(1)指针类型定义

声明:

type 指针类型名 = ^基类型

(2)指针类型操作

示例:

1    var

2      X, Y: Integer;   // X 和 Y 为 Integer 变量

3      P: ^Integer;     // P指向 Integer 数据

4    begin

5      X := 17;         // 为 X 赋值

6      P := @X;         // 将 X 的地址赋予 P

7      Y := P^;         // 取 P 所指地址的内容赋予 Y

8    end;

在上述代码中:

第2行将X和Y声明为Integer型变量。

第3行将P声明为指向Integer数值的指针。

第5行为X赋值。

第6行将X的地址赋予P。

第7行取P所指地址中的数据赋予Y。

 

注意

符号“^”有两个作用。当它位于类型标识符之前时,表示指向该类型变量的指针;位于指针变量之后时,表示取出该指针所指地址中的内容。

① @操作符

@操作符用于获得操作数的地址,构造指向其后操作数的指针。

② New过程

New过程创建一个新的动态变量,并将它的内存地址赋给一个指针变量。

语法:

New(指针类型变量)

③ Dispose过程

Dispose过程释放由New过程为动态变量所分配的内存。

语法:

Dispose(指针类型变量)

(3)无类型指针

无类型指针用类型标识符Pointer声明,它可以指向任意数据类型,有“万能”(versatile)指针之称。

var  P: Pointer;

注意:对无类型指针变量不能做取值操作,在此类变量之后放置“^”符号将引发编译错误。若需访问Pointer变量所引用的数据,应将该变量映射为另一有类型指针,然后对后者取值。

第5节运算符与表达式

本节要点

l         常用运算符

l         运算符的优先级

 

由常量、变量、函数、运算符以及括号连接起来的有意义的式子称为表达式。

一、赋值运算符

:=

 

二、算术运算符

*、/、div(整除)、mod(取余)、+、-。

三、逻辑运算符

not、and、or、xor。

四、关系运算符

=、<>、>、<、>=、<=。

五、位运算符

not、and、or、xor、shl(左移)、shr(右移)。

六、指针运算符

@(取地址,在变量名左侧)、^(取内容,在指针变量右侧)、+、-、=、<>。

七、集合运算符

+(并)、-(差)、*(交)、<=(包含于)、>=(包含)、=(相等)、<>(不相等)、in(属于)

其中 +、-、* 的运算结果为集合,其他运算符的运算结果为逻辑值。

八、其他运算符

1. 字符串运算符

+

2. 类运算符

is、as

九、运算符的优先级

分类

运算符

优先级

单目

@, not

最高

乘除

*, /, div, mod, and, shl, shr, as

第二

加减

+, -, or, xor

第三

关系

=, <>, <, >, <=, >=, in, is

最低

注意

逻辑运算符分布在不同级别,并且优先级高于关系运算符,因此,在逻辑表达式中应当用括号将逻辑运算符两侧的操作数括起来。例如:

(X= Y) or (X = Z)

第6节语句

本节要点

l         声明语句

l         简单语句与复合语句

l         条件控制语句

l         循环语句

 

一、声明语句

1. Delphi中的“块”(补充)

(Blocks)是Delphi中的一个特殊术语,前面讨论的标识符声明和各种语句都被组织到“块”中。块由一系列声明(变量、常数、类型、过程、函数)和一个复合语句构成。在块中,所有声明必须出现在块的起始处。块的格式如下:

声明部分

begin

  语句系列

end

块是程序、函数或过程声明的组成部分。每个程序、函数或过程声明均含有一个块。

2. 声明的位置

在Delphi中,声明(类型、常量、变量等)语句只能出现在以下特定位置:

l        块的起始处(begin之前);

l        单元接口区(interface)的起始处(uses子句之后);

l        单元实现区(implementation)的起始处(uses子句之后)。

3. 关于作用范围

标识符(如常量、变量、过程名或函数名)只能在其声明的作用范围(作用域,Scpope)中使用。声明的位置决定其作用范围

在程序、函数或过程声明内声明的标识符,其作用范围从声明的位置开始,并且局限于声明它的块中。

在单元的接口部分声明的标识符,其作用范围包括本单元以及使用该单元的其他单元或程序。

作用范围较窄的标识符,特别是在函数或过程中声明的标识符称为局部(local)标识符;作用范围较宽的标识符称为全局(global)标识符。

二、简单语句与复合语句

1. 赋值语句

变量:= 表达式;

2. 复合语句(补充)

复合语句(Compound statements)是用beginend括起来的一组语句,通常出现在块中。例如:

begin

  Z := X;

  X := Y;

  Y := Z;

end;

此外,复合语句亦常出现在单句形式的结构化语句中(如if、for、while等),其地位相当于一条语句。例如:

begin

  I := 10;

  while I > 0 do

  begin

    ...

    I := I - 1;

  end;

end;

三、条件控制语句

1. If语句

(1)语法

if 条件 then 语句1 [else 语句2];

条件”是一个结果为逻辑值的表达式。

注意

① 在then和else之间不能出现分号(复合语句内者除外)。若语句1为复合语句,并且其后有else子句,则复合语句的end后亦不能出现分号。

② 在嵌套的if语句中,else与最接近它的if配对。

③ 为了避免语法格式出错,提高代码输入速度,可在输入“if”后,按Ctrl+J键,从弹出的列表中选择所需代码框架模板。

(2)示例

例1:

ifx >= 0 then

  y := x;

例2:

ifx >= 0 then

  y:= x

else

  x := y;

例3:

ifx >= 0 then

  begin

    y := 1;

    z := 2;

  end  // 不加分号

else

  begin

    y := 3;

    z := 4;

  end;

例4:

ifx > 0 then

  y := 1   // 无分号

elseif x = 0 then

        y := 0   // 无分号

      else

        y := -1; // if语句结束,有分号

例5:

在单行文本框(Edit)中限制用户输入合法数据。例如,有时只允许用户输入数字(如邮政编码、职工编号等),可在文本框的OnKeyPress事件过程中用以下代码过滤掉键盘输入的非数字字符:

procedureTForm1.Edit1KeyPress(Sender: TObject; var Key: Char);

begin

  { OnKeyPress事件中的Key参数传送的是用户按键的ASCII码字符。

    in为集合运算符,#8为退格键,Key:= #0表示取消按键 }

  if not (Key in['0'..'9', #8]) then Key := #0;

end;

2. Case语句

(1)语法

case 选择表达式 of

 值表1:语句1;

 ...

 值表n:语句n;

[ else

  语句n+1;]

end

说明:

选择表达式”必须是有序类型,不能是字符串类型。

值表”规定如下:

① 可以是数字、已声明的常数或能够直接得出值的表达式(如2+3*5),且必须是与“选择表达式”相容的有序类型。不能是变量。除了下列函数外,不得使用其他函数:Abs、Chr、Hi、High、Length、Lo、Low、Odd、Ord、Pred、Round、SizeOf、Succ、Trunc。

② 可以是满足上述标准的子界类型,如:1..100。

③ 可以是满足上述标准的项目列表,如:0,10..20,30,50..60。

④ 每一个值必须惟一,子界或项目列表不能重叠。

语句”是以分号分隔的语句序列。若某个值表中的值与选择表达式相等,则执行该值表冒号后的语句,然后直接跳转到end后面的语句。如果有else子句,当各值表中没有与选择表达式相等的值时,则执行else后面的语句n+1。

(2)示例

var

  Sc: Integer;

  Gr: string;

...

caseSc of

  0..59: Gr:= '不及格';

  60..79: Gr:= '及格';

  80..89: Gr:= '良';

  90..100: Gr:= '优';

else

  ShowMessage('成绩输入错误。');// 显示消息对话框

end;

四、循环控制语句

1. For循环

(1)语法

两种形式:

for 循环变量:= 初值 to 终值 do 循环体// 循环变量每次加1

for 循环变量:= 初值 downto 终值 do 循环体// 循环变量每次减1

说明:

l        循环体可以是一个简单语句或复合语句。

l        在循环体中不得改变循环变量值

l        循环变量必须是有序类型,且与初值和终值类型相同。

l        循环结束后循环变量的值自动设置为不确定的值。

l        初值和终值仅在循环开始前计算一次。

(2)示例

vari, sum: Integer;

...

sum:=0;

fori:= 1 to 100 do  // 求1+2...+100

  sum:= sum + i;

2. While循环

(1)语法

while 条件 do 循环体

条件为真时循环。循环体可以是一个简单语句或复合语句。

(2)示例

vari, sum: Integer;

...

i:=1;

sum:=0;

whilei<= 100 do

 begin

   sum:= sum + i;

   i:= i+1;

 end;

3. Repeat循环

(1)语法

repeat 循环体 until 条件;

条件为真时停止循环。循环体可以是多条语句。至少执行一次循环体。

(2)示例

vari, sum: Integer;

...

i:=1;

sum:=0;

repeat

  sum:= sum + i;

  i:= i+1;

untili > 100;

五、其他语句

1. Break语句

Break语句用于退出循环。该语句必须出现在循环语句的循环体中。

例如:

vari, sum: Integer;

...

sum:=0;

fori:= 1 to 100 do // 求1+2...+100

begin

  sum:= sum + i;

  if sum > 2000 then break; // 若总和大于2000,退出循环

end;

2. Continue语句

Continue语句用于结束本次循环,直接进入下一次循环。该语句必须出现在循环语句的循环体中。

例如:

求1~100中的偶数之和。

vari, sum: Integer;

...

sum:=0;

fori:= 1 to 100 do

begin

  { Odd函数用于判断某数是否为奇数,若i为奇数,直接进入下一次循环 }

  if Odd(i) then continue;

  sum:= sum + i;

end;

3. exit语句

该语句用于退出当前程序块,通常位于分支语句中。

4. halt语句

该语句使程序异常终止,返回到操作系统。

若要使程序正常终止,可以调用全局对象Application的Terminate方法。

六、With语句

with语句的作用主要是用来简化代码。例如下面的代码:

Form1.Canvas.Pen.Width:=2;

Form1.Canvas.Pen.Color:=clRed;

可以用with语句简化为:

withForm1.Canvas.Pen do

begin

  Width:=2;

  Color:=clRed;

end;

第7节过程和函数

本节要点

l         过程与函数的声明

l         过程与函数的调用

l         参数

 

过程和函数统称为例程(routines)。函数有返回值,过程无返回值。

一、过程和函数的声明

(1)过程声明

procedure过程名([参数表]);  // 过程首部

  局部变量声明;

begin

  过程体语句

end;

(2)函数声明

function函数名([参数表]):返回值类型;  // 函数首部

  局部变量声明;

begin

  函数体语句

end;

(3)关于函数的返回值

在函数中,函数名本身相当于一个特殊变量,在函数体内对函数名赋值即可为函数指定返回值。可以对函数名赋值多次,但只有最后一次被作为返回值。

此外,Delphi为所有函数声明了一个隐含变量Result,对该变量赋值亦可指定返回值。例如,以下两个函数声明等价:

functionWF: Integer;

begin

  WF :=100;

end;

 

functionWF: Integer;

begin

  Result := 100;

end;

 

注意:在函数体内,仅当函数名出现在赋值语句(赋值号)的左侧时,才与隐含变量Result的作用相同,即指定返回值。如果函数名出现在其他位置,则被当作本函数的递归调用处理。Result无论出现在何处,它的作用只是一个含有返回值的变量,在函数体内可以对Result本身进行操作。

 

(4)过程和函数的作用范围

过程和函数的作用范围取决于其声明的位置,若在其声明位置之前调用它们,将会引发错误。因此,在单元的实现部分,如果不进行特殊处理,应当先声明被调过程或函数,后声明主调过程或函数。

如果需要扩展自定义过程或函数的作用范围,可以预先声明过程或函数的首部(或称原型、标题)。方法如下:

① 使用forward指令

在单元实现部分的编译指令{$...}之后(若有uses子句,应在它之后),声明带有forward指令(超前声明)的函数或过程的首部,格式如下:

procedure过程名([参数表]);forward;  // 过程forward声明

或:

function函数名([参数表]):返回值类型; forward;  // 函数forward声明

在forward声明之后的某个位置进行定义声明(defining declaration),定义不带forward指令的函数体或过程体。

注意:在超前声明和定义声明之间不允许出现变量(var)和常量(const)声明区。

用forward指令声明的函数或过程仅供本单元调用。

② 在单元的接口部分声明函数或过程的首部

接口部分声明函数或过程的首部,然后在实现部分进行定义声明。用这种方法声明的函数或过程可供本单元以及使用本单元的其他单元和程序调用。在接口部分不能使用forward指令。

采用上述两种方法时,定义声明中可以省略参数,亦可省略函数的返回值类型。

二、过程和函数的调用

过程调用:

过程名(参数表);

函数调用:

函数名(参数表)

在默认情况下,函数调用既可以出现在表达式中,亦可像过程调用一样作为一个语句使用(此时忽略返回值)。

三、参数

Delphi中的参数传递分为4种方式:值参数、变量参数、常量参数和输出参数。值参数为默认方式,其余三种分别用保留字var、const和out标识。

1. 值参数

值参数(Value parameters)简称值参,是默认的参数传送方式(传值)。值参改变时不影响实参值。例如:

functionMyFuncVal(X: Integer): Integer;

begin

  X := X * 2;

  Result := X;

end;

2. 变量参数

变量参数(Variable parameters)简称变参,又称引用参数(传址),在形参前使用var关键字声明。由于变参与实参共用同一内存地址,因此实参值将随变参变化。例如:

functionMyFuncRef(var X: Integer): Integer;

begin

  X := X * 2;

  Result := X;

end;

注意

过程或函数调用时,与变参对应的实参不允许使用常量或表达式。

3. 常量参数

常量参数(Constant parameters)类似于局部常量或只读变量,在形参前使用const关键字声明。调用过程或函数时,实参、形参均不改变,可保护变量值不被改变。使用常量参数可以优化代码的编译。

在过程体或函数体内不允许对常量参数赋值。可以将常量参数作为实参传递给另一个过程或函数,但对应的形参必须是值参常量参数,而不能是变参

下面通过示例说明常量参数的使用规则。

以下函数的形参为值参

functionFuncVal(X: Integer): Integer;  // X为值参

begin

  X := X * X;

  Result := X;

end;

以下函数的形参为变参

functionFuncRef(var X: Integer): Integer; // X为变参

begin

  X := X * X;

  Result := X;

end;

以下函数的形参为常量参数,在函数体内调用了上面已声明的函数。请注意常量参数的使用规则:

functionFuncConst(const Y: Integer): Integer; // Y为常量参数

begin

  Y := Y * 2; // 非法! 不允许对常量参数赋值

  Result := FuncRef(Y) * 2;  // 非法! 不允许将常量参数作为变参传递

  Result := FuncVal(Y) * 2;    // 合法。可以将常量参数作为值参传递

end;

4. 数组参数

常用开放式数组作形参,始终以0为下界。

参数格式:

(参数名:array of 类型)

5. 默认参数(补充)

声明过程或函数时可在首部指定参数的默认值,被指定了默认值的参数称为默认参数。默认值仅适用于值参和类型化的常量参数,不允许为变参指定默认值。

例如:

procedureP1(a: Integer; b: Integer = 100); // 参数b的默认值为100

又如:

procedureP2(x: Integer; const y: Integer = 0);// 参数y的默认值为0

默认参数只能出现在参数列表的最后。例如,以下声明是非法的:

procedureP3(a: Integer = 0; b: Integer = 1; c: Real);

以下声明是合法的:

procedureP4(a: Integer; b: Integer = 1; c: Real = 3.14);

允许将过程或函数的全部参数均设置为默认参数。例如:

procedureP5(a: string = 'ABC'; b: Integer = 1; c: Real = 3.14);

调用过程或函数时可省略默认参数(该参数取默认值)。例如,调用上面声明的过程P1时,以下两个调用语句等价:

P1(x);

P1(x,100);

在调用含有多个默认参数的函数或过程时,如果省略了其中某个默认参数,则必须同时省略它后面的所有参数。例如,调用上面声明的过程P5时,以下调用语句是非法的:

P5('',, 3.14159);

6. 输出参数(补充)

输出参数(Out parameters)按地址传递(与变参相似),但它仅用作输出,只将存放输出信息的地址(即实参)通知函数或过程,不向函数或过程内传送任何数据。

当调用带有输出参数的函数/过程时,系统首先将输出参数对应的实参清空(即不保留实参值),然后才执行函数/过程体。无论在函数/过程体内是否对输出参数赋值,该参数对应的实参原始值都将丢失。这一特点是输出参数和变量参数最重要的区别。

将一个未经初始化的变量作为实参传递给函数/过程时,应当使用输出参数。

 

练习

1. 限制用户输入合法数据

在第1章“练习2”的基础上,根据本章第6节“三、条件控制语句”所述,将学号和年龄文本框设置为只能输入数字字符。

2. 成绩分等

编制程序,根据用户输入的分数显示成绩等级:90~100:优;80~89:良;70~79:中;60~69:及格;60以下:不及格。要求用Case语句。

3. 用辗转相除法求最大公约数

编制一个自定义函数,用辗转相除法求两个数的最大公约数。

辗转相除法是以两数相除取余,若余数为零,则除数即为最大公约数。若余数不为零,则将除数改作被除数,余数改作除数,继续相除,直至余数得零为止。在最后一次相除时所用的除数(即最后一个不为零的余数),就是所求两数的最大公约数。整个过程可以用循环实现。

用“辗转相除法”求最大公约数的计算方法如下:

⑴ 两数相除(m除以n),取余数r;

⑵ 若r≠0,则将除数改作被除数,余数改作除数(m←n,n←r),重复步骤⑴、⑵,直到r = 0为止;

⑶ 最后一次相除时所用的除数就是最大公约数。

 

可能用到的标准函数:

将数字字符串转换为整数:StrToInt(数字字符串)

将整数转换为字符串:IntToStr(整数)

原创粉丝点击