分数我要呀,刚才机器被人借了,又不高兴玩VFP,所以翻译了文章,正好有用:
Delphi 4 语言增强
by Dr. Bob
Translated by CJ
--------------------------------------------------------------------------------
Inprise 公司的 Borland Delphi 4 在 Object Pascal 语言方面进行了一系列增强。像往常一样,在这篇文章里,我会解释一个十分艰巨的改进,那是从开放试参数(Open Parameters)和长字符串(Long String)回到基本的数组的动态数组(Dymantic Array)。
Dynamic Arrays
在 Delphi 4,我们除了可以像往常一样说明静态数组外:
X: Array[1..42] of String;//传统的静态数组
我们现在可以说明动态数组。动态数组指定类型信息(维数和元素类型)但不是元素的数量,因此:
X: Array of String;
M: Array of Array of Integer;
定义了两个动态数组。X是字符串类型的一维数组,M是一个整数类型的二维数组 (像一个 矩阵)。
动态数组没有一个固定大大小或者长度。取而代之,当执行SetLength过程或者给其赋值时,会为这个动态数组(重新)分配内存。因此,以上对X和M的定义并没有分配内存。在内存中建立数组时,调用SetLength过程。例如对于以上的说明:
SetLength(X, 42);
分配了42个字符串的数组,下标从0 到 41。动态数组总是整数为下标的且总是从0开始。
在调用SetLength以后, 以前动态数组中的内容(如果有)也被随之复制i(所以,即便我们经常增加或减小数组的长度,数据也不会丢失)。使用以上知识,我们可以写一个小,当然是低效率的程序,用来读多行文本文件的内容,并且只分配需要数量的字符串。
{$R+}
{$APPTYPE CONSOLE}
var
X: Array of String;
i: Integer;
begin
while not eof do
begin
SetLength(X,Length(X)+1)
// very inefficient...
readln(X[High(X)])
end;
for i:=0 to High(X) do writeln(X)
end.
动态数组变量是隐含的指针,并且被长字符串那样的reference-counting技术所管理。释放动态数组,赋给动态数组一个Nil值,或使用Fiinalize过程。这两种方法清除数组,前提是没有其它引用存在。
{$R+}
program Delphi4;
{$APPTYPE CONSOLE}
uses
Dialogs;
var
X,Y: Array of String;
i: Integer;
begin
SetLength(X, 7);
Y := X;
X[3] := 'Dynamic Arrays in Delphi 4';
SetLength(X, 42);
Y := X;
SetLength(Y, 4);
ShowMessage(Y[3]);
X := nil;
Finalize(Y);
end.
警告: 我们不能对一个动态数组变量使用使用操作符^ 用在New和Dispose过程。
如果X和Y是同一动态数组类型的变量,X:=Y分配给X和Y同样的长度,并把X指向Y的同一个数组。不想字符串,数组在它们被写入前是不会自动被复制的,但是,它们保持指向相同处—共享内存区!例如,在以下代码被执行:
var
X,Y: array of String;
begin
SetLength(X, 1);
X[0] := 'Hello, world';
Y := X;
Y[0] := 'Answer';
end;
X[0]的值是 'Answer'。
长字符串会在我们改变其中一个时,他们“分裂开来”(建立独立的拷贝),而动态数组保持指向相同的区域。这也许会有些遗憾,不过,至少我们不会像长字符串那样在性能上有所损失...
当然,由于动态数组的内容会在我们调用SetLength时被复制,它也会(在调用SetLength时)建立一个独立的拷贝。
对动态数组下标赋值(例如 X[42] := 'Answer')不会从新分配内存(如果要那样,我们需要调用SetLength)。下标越界在编译时不会被发现,但是会在运行期间产生异常。 (使用 $R+ 编译指令)。
当动态数组变量比较时,其引用被比较,不是其数组的值。所以,以下代码执行后:
var
X, Y: array of String;
begin
SetLength(X,1);
SetLength(Y,1);
X[0] := 'Hello, world!';
Y[0] := 'Hello, world!';
end;
X = Y 返回 False 但是 X[0] = Y[0] 返回 True。
截断动态数组,把自身传递给Copy函数,然后再把返回结果赋予自身。例如,如果X是一个动态数组, X := Copy(X, 0, 2)只保留前三个元素,其余均被截断。
一旦动态数组被分配内存,我们可以把它传递到标准函数Length,High,Low中。Length返回数组中元素的个数;High返回数组中可能最大的下标(Length - ); Low永远返回0。一个长度为0的数组High返回-1,所以,在那种情况下,High(X) <Low(X)。
为了展示多维动态数组M (参见本页最上面的说明部分)我们需要调用有两个整数类型参数的 SetLength:
SetLength(M,10,5);
分配了一个10*5的数组,M[9,4] 为其中的一个元素。
我们也可以建立非矩形的多维动态数组。 首先我们要调用SetLength,其参数为数组第一维的数字n,例如:
var
M: array of array of Integer;
begin
SetLength(M,10);
为M分配了10行,但是没有分配列。然后,我们可以每次分配一列(给其不同的长度)。例如:
SetLength(M[2], 42);
使第三列有42个整数类型长。在这里(即使其它列还未被分配)我们可以为第三列赋值。例如:M[2,41] := 7。
--------------------------------------------------------------------------------
This webpage &#169
1999 by webmaster drs. Robert E. Swart (aka Dr.Bob - www.drbob42.com). All Rights Reserved.