• 变量指针和函数参数


    一.参数类型 Object Pascal语言允许五种类型的参数(不是指参数的数据类型),分别是数值参数、常量参数、变量参数、 无类型的参数、开放数组参数。 不管是哪一种参数类型,在调用过程或函数时,实参跟形参在个数上必须相同,在数据类型上必须赋 值相容。 -------------------------------------------------------------------------------- 数值参数 数值参数是一种最常见的参数,当调用过程或函数时,程序把实参的值复制一个副本,传递给数值参 数,数值参数对过程或函数而言是局部变量,对数值 参数的修改不会直接改变实参的值。 注意:作为实参传递给数值参数的值不能是文件类型或包含文件类型的构造类型。 -------------------------------------------------------------------------------- 常量参数 常量参数跟数值参数的区别在于,常量参数是只读的,也就是说不允许在过程或函数中改变中改变常 量参数的值,对常量参数赋值是非法的,并且不允许把常量参数再作为实参传递给另一个过程或函数。例 如下列程序中包含了不合法的代码: Procedure Myproc(Const Value:Integer); {参数名前加Const表示是常量参数} Begin Value:=3;{非法!因为不允许对常量参数赋值} AnotherProc(Value);{非法,常量参数不能再作为实参传递给另一个过程或函数} End; -------------------------------------------------------------------------------- 变量参数 变量参数有点像C++的引用,参数在传递时传递的不是实参的副本, 而是实参的地址, 这 样当参数在过程或函数中被改变时,实参的值也相应改变,在过程或函数中对形参的引用实际上就是 对实参自身的引用。 程序示例如下: procedure MyProc(Var Value:Integer); {参数名前加VAR表示是变量参数} Begin Value:=3; End; Procedure TForm1.Button1Click(Sender:Tobject); Var X:Integer; Begin X:=2 Myproc(X); End; 当形参是变量参数时,实参也必须是一个变量而不能是一个表达式,例如上例中这样调用就是非法 的:MyProc(2);另外实参跟形参的数据类型必须完全 一致而不仅仅是赋值相容。 当形参是变量参数时,实参可以是文件类型或包含文件类型的构造类型。 当参数是构造类型时,使用变量参数具有优势,因为如果使用数值参数,在调用时必须分配足够大 的内存空间来存放实参的副本,当参数比较庞大时,将花费大量的空间和时间,而使用变量参数时,传 递的仅仅是实参的地址,其效率是显而易见的。 -------------------------------------------------------------------------------- 无类型参数 所谓无类型参数,就是在过程或函数声明和定义时不指定参数的数据类型,程序示例 如下: Procedure MyProc(Var Value); 上例中,Value参数没有指定数据类型,但前面必须加Var或const,加Var表示参数的值是可以改 变的,加Const表示参数是只读的。 当参数是无类型参数时,实参可以是任意数据类型的变量或表达式,使用无类型参数可以使程序 编制更加灵活,但也给编译器带来麻烦,因为它没法对 参数进行合法性检查。 正因为参数是无类型的,因此在使用前最好先进行类型强制转换,把它转换成某种特定的数据类 型,程序示例如下: Procedure Myproc(Var Value); Type TMyArray=arrayp[1..10] of Integer; Var I:integer; Begin for i:=1 to 10 Do TmyArray(Value)[i]:=i; End; 过程或函数本身作为参数 在Object Pascal中,允许把过程或函数本身作为参数来传递,因为过程或函数也可以看作一种数据类型。 不能把标准的过程或函数作为参数,而只能把您自己定义的过程或函数作为参数传递。 二:Object Pascal语言中的“指针类型” ⒈指针类型的声明 指针类型的声明 指针类型在任何语言中都是比较难理解也是比较灵活的一种数据类型,指针通常是它所指的变量的内存地址。 声明指针类型的语法如下: Type 指针类型标识符=^基类型; 程序示例如下: Type BytePtr=^Byte; WordPtr=^Word; 上例中,声明了两个指针类型,一个是bytePtr,指向byte类型的数据,另一个是WordPtr,指向word类型的数据。 Object pascal不表示基类型一定要是在前面已声明的,也可以只是一个标识符,然后在同一个块内声明基类型。 声明了指针类型之后,就可以声明指针类型的变量,例如: Var BP:BytePtr; WP:WordPtr; 为了简化程序,也可以把类型的声明和变量的声明合并在一起,例如: Var BP:^Byte; 指针所指的基类型可以是简单类型,也可以是构造类型,例如: Type Student=Record name:String; Age:Integer; Sex : (Man, Woman); End; Var StuPtr:^Student; 上例中,声明了一个指向记录类型Student的指针变量Studptr,以后程序中就可以用StuPtr^来表示记录类 型的Student的动态变量,要访问其中的Name字段,可以写成StuPtr^.Name。 这里介绍动态变量的概念,动态变量是这样构成的,用指针类型的变量标识符后加一个^符号,就构成指针 所指向的基类型的动态变量,像上例中的StuPtr^就是Stduent的动态变量。 (在Delphi程序中,很多程序都习惯这样声明 Type PStudent=^TStudent; TStudent=Record name:string; Age:Integer; Sex : (Man, Woman); End; ) ⒉指针的操作 实际上前面已介绍了指针的简单用法,这里还要介绍几个用于指针操作的过程和操作符。 New是object pascal中的标准例程(System 单元声明),用于在应用程序的堆中为动态变量分配一块区域, 并把该区域的地址赋给指针变量,所分配区域的大小由指针所指的类型决定。如果应用程序的堆上已没有足 够的空间,将触发EOutOfMemory异常。 New过程的声明如下: Procedure New(var P:Pointer); 其中P是一个指针变量,调用了New过程之后,程序就可以用p^作为指针所指类型的动态变量。 相应地,用当程序不再需要使用动态变量时,就应当调用标准例程Dispose删除New创建的动态变量,并释放 所分配的空间。 程序示例如下: Type PListEntry=^TListEntry; TListEntry=Record Next:PListEntry; Text:string; count:Integer; End; Var List,P:PlistEntry; Begin … New(P); P^.Next:=List; p^.Text:='Hello World'; p^Count:=1; List:=P; Dispose(P); … End; 上例中,首先声明了一个指针类型PListEntry,指向TListEntry类型,TListEntry类型的声明在下面,是一 个记录类型。然后声明了两个PListEntry类型的变量List和P。 Object Pascal中还有一个例程GetMem,其作用与New差不多,也是在应用程序的堆中为动态变量分配一块区 域,并把该区域的地址赋给指针变量,不同的是GetMem例程指定了要分配区域的大小,GetMem的声明如下: Procedure GetMem(Var P:Pointer;Size:Integer); 其中P是指针变量,Size是字节数。 相应地,用GetMem创建的动态变量必须用FreeMem例程删除,并释放分配的空间。 Object Pascal语言中还有一个@操作符,用于获得操作数的地址,操作数可以是变量、过程、函数或类类型 中的方法,关于@操作符的详细介绍请参考操作 符。 Object Pascal中有一个特殊的保留字nil,这是个空指针常量,当指针的值为nil时,表示指针当前没有指 向任何动态变量。注意:您不能用值为nil的指针变 量去访问动态变量。 指针变量除了能被赋值以外,还能进行相等或不相等的比较,比较只限于类型兼容的指针变量之间。当两个 指针指向同一个对象时(不是同一个类型)指针才 相等。 ⒊无类型指针 无类型的指针是指指针变量声明时没有有确地给出基类型,无类型的指针是这样声明的: Var Ptr:Pointer; 无类型指针的作用在于它可以指向任何类型,不过对于无类型的指针,您不能用类似ptr^的形式来引用它的 动态变量。 三:类型常量 ⒈简单类型的常量 简单类型的常量是指常量的值为简单类型(有序类型和实型)的类型常量,例如: Const Maximum:integer=9999; Factor:Real=-0.1; BreakChar:Char=#3; 上例中,声明一个整型的常量Maximum,一个实型的常量Factor,一个控制字符型的常量BreakChar。 ⒉指针类型的常量 指针类型的常量通常是用"常量地址表达式"来声明的,对于Pchar类型的类型常量,可以用一个字符串赋值。 指针类型的常量示例如下: Type TDirection=(Left,Right,Up,Down); PNode=^Node; TNode=Record Next:PNode; Symbol:String; Value:TDirection; End; Const N1:TNode=(Next:nil;Symbol:'DOWN';Value:Down); N2:TNode=(Next:@N1;Symbol:'UP';Value:Up); N3:TNode=(Next;@N2;Symbol:'RIGHT';Value:Right); N4:TNode=(Next;@N3;Symbol:'LEFT';Value:Left); Const DirecTionTable:PNode=@N4; 上例中,首先声明了一个枚举类型TDirection,一个指针类型PNode,一个记录类型TNode,其中Next 字段是PNode类型。 然后声明了四个记录类型的常量,其中Next 字段的值是用指针类型的常量给出的,N1的Next字段的值 是nil,诸如此类。 最后声明了一个指针类型的常量DirectionTable,它的值是记录常量N4的地址。 ⒊过程类型的常量 过程类型的常量声明的语法如下: Const 常量名称:过程类型=初始值; 声明一个过程类型的常量只需给出过程或函数名,给出的过程或函数必须与常量的类型赋值兼容,也就 是说,参数个数和顺序以及参数的类型必须一致,否则只能指定nil. 程序示例如下: Type TErrorProc=procedure (ErrorCode:Integer); Procedure DefaultError(ErrorCode:Integer); Begin WriteLn('Error',ErrorCode,'.'); End; Const ErrorHandler:TErrorProc=DefaultError; 上例中,首先声明了一个过程类型TErrorProc,然后定义了一个名为DefaultError的过程,最后声明 了一个过程类型的常量ErrorHandler,它的值是DefaultError过程。 ⒋构造类型的常量 如果要声明一个构造类型的常量,必须给出构造类型的各个分量的值,实际上我们已经介绍了记录类 型的常量,除了记录类型的常量之外,还可以声明数组类型和集合类型的常量,但不能明文件类型的 常量或包含文件类型分量的记录类型的常量。 声明一个数组类型的常量必须给出所有的元素,其语法如下: Const 常量名=(分量值1,分量值2...分量值n); 数组类型的常量的各个元素由一对圆括号括起来,每个分量之间用逗号分隔。例如: Type TStatus=(Active,Passive,Waiting); TStatusMap=Array [TStatus] of string; Const StatStr:TStatusMap=('Active','Passive','Waiting'); 上例中,首先声明了一个枚举类型TStatus,然后声明了一个数组类型,其下标类型是TStatus,其基 类型是String,最后声明一个TStatusMap类型的数组类型常量,它的三个元素的值分别是'Active', 'Passive',"Waiting'。 对于基类型是字符的数组,在声明时可以用一个字符串作为常量的值,例如: Type TStatusMap=Array [1..11] of Char; Const StatStr:TStatusMap='This is way'; 要声明集合类型的常量,常量的值是用方括号括起来的集合常量,例如: Type Digits=Set Of 0..9; Letters=Set Of 'A'..'Z'; Const EvenDigits:Digits=[0,2,4,6,8]; Vowels:Letters=['A','E','I','O','U']; 上例中,首先声明了两个集合类型,然后声明了二个集合类型的常量,如EvenDigits表示偶数的集合, Vowels表示元音字母的。 Procedure MyProc: Var X,Y,Z:integer; Begin … End 上例中,X,Y,Z只是在过程MyProc内有定义。 对于局部变量而言,不能在声明时赋初值,在明确地给它们赋值之前,它们的值是不确定的。 五:类型常量 ⒈简单类型的常量 简单类型的常量是指常量的值为简单类型(有序类型和实型)的类型常量,例如: Const Maximum:integer=9999; Factor:Real=-0.1; BreakChar:Char=#3; 上例中,声明一个整型的常量Maximum,一个实型的常量Factor,一个控制字符型的常量BreakChar。 ⒉指针类型的常量 指针类型的常量通常是用"常量地址表达式"来声明的,对于Pchar类型的类型常量,可以用一个字符串赋值。 指针类型的常量示例如下: Type TDirection=(Left,Right,Up,Down); PNode=^Node; TNode=Record Next:PNode; Symbol:String; Value:TDirection; End; Const N1:TNode=(Next:nil;Symbol:'DOWN';Value:Down); N2:TNode=(Next:@N1;Symbol:'UP';Value:Up); N3:TNode=(Next;@N2;Symbol:'RIGHT';Value:Right); N4:TNode=(Next;@N3;Symbol:'LEFT';Value:Left); Const DirecTionTable:PNode=@N4; 上例中,首先声明了一个枚举类型TDirection,一个指针类型PNode,一个记录类型TNode,其中Next 字段是PNode类型。 然后声明了四个记录类型的常量,其中Next 字段的值是用指针类型的常量给出的,N1的Next字段的值 是nil,诸如此类。 最后声明了一个指针类型的常量DirectionTable,它的值是记录常量N4的地址。 ⒊过程类型的常量 过程类型的常量声明的语法如下: Const 常量名称:过程类型=初始值; 声明一个过程类型的常量只需给出过程或函数名,给出的过程或函数必须与常量的类型赋值兼容,也就 是说,参数个数和顺序以及参数的类型必须一致,否则只能指定nil. 程序示例如下: Type TErrorProc=procedure (ErrorCode:Integer); Procedure DefaultError(ErrorCode:Integer); Begin WriteLn('Error',ErrorCode,'.'); End; Const ErrorHandler:TErrorProc=DefaultError; 上例中,首先声明了一个过程类型TErrorProc,然后定义了一个名为DefaultError的过程,最后声明 了一个过程类型的常量ErrorHandler,它的值是DefaultError过程。 ⒋构造类型的常量 如果要声明一个构造类型的常量,必须给出构造类型的各个分量的值,实际上我们已经介绍了记录类 型的常量,除了记录类型的常量之外,还可以声明数组类型和集合类型的常量,但不能明文件类型的 常量或包含文件类型分量的记录类型的常量。 声明一个数组类型的常量必须给出所有的元素,其语法如下: Const 常量名=(分量值1,分量值2...分量值n); 数组类型的常量的各个元素由一对圆括号括起来,每个分量之间用逗号分隔。例如: Type TStatus=(Active,Passive,Waiting); TStatusMap=Array [TStatus] of string; Const StatStr:TStatusMap=('Active','Passive','Waiting'); 上例中,首先声明了一个枚举类型TStatus,然后声明了一个数组类型,其下标类型是TStatus,其基 类型是String,最后声明一个TStatusMap类型的数组类型常量,它的三个元素的值分别是'Active', 'Passive',"Waiting'。 对于基类型是字符的数组,在声明时可以用一个字符串作为常量的值,例如: Type TStatusMap=Array [1..11] of Char; Const StatStr:TStatusMap='This is way'; 要声明集合类型的常量,常量的值是用方括号括起来的集合常量,例如: Type Digits=Set Of 0..9; Letters=Set Of 'A'..'Z'; Const EvenDigits:Digits=[0,2,4,6,8]; Vowels:Letters=['A','E','I','O','U']; 上例中,首先声明了两个集合类型,然后声明了二个集合类型的常量,如EvenDigits表示偶数的集合, Vowels表示元音字母的。 要声明记录类型的常量,必须给出记录的各个字段的值,例如: Type Tpoint=Record X,Y:Single; end; TVector=Array[0..1] of TPoint; TMonth=(jan,Feb,Mar,Apr,May,Jun,Jly,Aug,Sep,Oct,Nov,Dec); Tdata=Record D:1..31; M:Month; Y:1900..1999; end; Const Origin:TPoint=(X:0.1;Y:0.2); Line:TVector=((X:-3.1;Y:1.5),(X:5.8;Y:3,0)); SomeDay:TData=(D:2;M:Dec;Y:1969); 上例中,实现声明一个记录类型TPOINT,它有两个字段X,Y,相应地声明类型常量Origin时,给出X字 段的值为0.1,Y字段的值为0.2。Line这个类型常量就复杂些,首先TVector是个基类型为TPoint的数 组,相应地声明类型常量Line时,首先按声明数组类型常量的要求给出它的两个元素的值,其中每个 元素又是一个记录类型,因此又必须分别给出每个字段的值。 声明记录类型的常量时要注意,字段的顺序必须与记录类型声明时的顺序一样,并且记录类型中不能 包括文件类型的分量。 综合合我们介绍的各种类型常量,您可以发现,类型常量的声明跟变量的声明很相似,事实上在程序 中类型常量可以当作变量使用,只是要注意一点,类型常量的值是不能改变的。 六:可变类型 ⒈什么是可变类型 从Delphi2.0起引起了一个新的数据类型Variant,它的确切类型在运行期是可变的,也就是说它可以 表示某些其它类型的值(除了Variant类型本身)。Variant类型主要用于当数据的类型在编译期是不确 定的或在运行期可能变化的情况。Variant类型具有如下特点: Variant类型不但可以表达一般的数据类型如整型、实型、字符串型、布尔型,还可以表示OLE自动化对 象,还可以表示长度和维数可变的数组。 Variant类型变量在被声明后总是被初始化为一个特殊的值Unassigned,表示该变量还没有赋值,如果 变量的值为Null,表示该变量的值是未知的或错误的。 Variant类型的变量可以同一般类型的数据出现在同一个表示式中,编译器将根据需要自动进行类型转 换。 当Variant的变量表示一个OLE自动化对象时,可以通过这个Variant类型的变量引用对象的特性和方法 等。 注意:尽管可变类型提供了许多编程上的灵活性,但要占用更多的内存空间和运行时间。 概要介绍: Object pascal语言的语句分为两大类,一是声明语句,一是执行语句,在Object Pascal中,凡是程序 中要用到的标号、常量、变量、过程、函数以及输出项首先要在程序的Type区或子程序的 Begin语句之 前声明,这就要用到声明语句。程序要完成一定的功能,离不开执行语句,执行语句又分为简单语句和 构造语句,像赋值语句就属于简单语句,条件语句和循环语句属于构造语句。 所谓块,就是语句的集合,不过它不仅仅是一些语句的简单罗列,块本身也必须遵循一定的语法规 则。
  • 相关阅读:
    find module providing package github.com/go-sql-driver/mysql: working directory is not part of a module
    深度学习中的epoch、batchsize、iterations的理解
    淘宝软件质量属性分析
    Git
    多线程
    Spark基础之Scala
    机器学习十讲第十讲
    机器学习十讲第九讲
    机器学习十讲第六讲
    本地MarkDown优雅发表
  • 原文地址:https://www.cnblogs.com/djcsch2001/p/2035719.html
Copyright © 2020-2023  润新知