to 杜宝:
关于开放数组/动态数组,我确实该说 ----------------- 我搞错了,没有经过测试,主观臆断,
就说了上面这么多的话。你是对的。引一段关于开放数组/动态数组的使用过程的 Delphi 帮助:
---------------------------------------------------------------------------------
Open array parameters allow arrays of different sizes to be passed to the
same procedure or function. To define a routine with an open array parameter,
use the syntax array of type (rather than array[X..Y] of type) in the parameter declaration.
For example,
function Find(A: array of Char): Integer;
declares a function called Find that takes a character array of any size and returns an integer.
Note: The syntax of open array parameters resembles that of dynamic array types,
but they do not mean the same thing. The example above creates a function that takes
any array of Char elements, including (but not limited to) dynamic arrays. To declare
parameters that must be dynamic arrays, you need to specify a type identifier:
type TDynamicCharArray = array of Char;
function Find(A: TDynamicCharArray): Integer;
Dynamic arrays do not have a fixed size or length. Instead, memory for a dynamic array is
reallocated when you assign a value to the array or pass it to the SetLength procedure.
Dynamic arrays are always integer-indexed, always starting from 0.
Dynamic-array variables are implicitly pointers and are managed by the same reference-
counting technique used for long strings. To deallocate a dynamic array, assign nil to a
variable that references the array or pass the variable to Finalize; either of these methods
disposes of the array, provided there are no other references to it. Dynamic arrays of length 0
have the value nil. Do not apply the dereference operator (^) to a dynamic-array variable or
pass it to the New or Dispose procedure.
-------------------------------------------------------------------------------------
正如帮助里所说:
1> 对于参数而言,array of XXXX 形式是开放式数组的表达;而对于变量定义才表示是动态数组。
形式相似,意义却不一样。
2> 如果你要保证传递的是一个动态数组,必须把该动态数组先申明成一个类型,然后传递。
3> 开放式数组在传入时,数组是固定的(大小和长度);而动态数组是不固定的(大小和长度),
它的大小可以通过使用 SetLength() 方法来调整。
也就是说:开放式数组作为参数时,允许重新对每个数组元素进行赋值,却不能用 SetLength()
重新分配数组大小。这是我在前面解答时犯的最大错误。现在予以更正。
4> 开放式数组在传入时有固定的大小,用户可以自己决定开放式数组的起始基数。因此在检查数组
界限时应该用 Low(open_array) / High(open_array) ;而动态数组一般(always 在这儿应该译为什么?
总是?)以 0 为基数(虽然说是 always,但实际上我也没发现可以改变起始基数的可能。在这一点,似
乎应该理解为“总是”,当然用 Low(dynamic_array) / High(dynamic_array) 更可靠)。
5> 动态数组变量实际上是一个显式的指针。动态数组在离开作用域时,会自动释放分配的内存(或者减少
引用计数);如果需要强制(显式)释放动态数组只要设置 DynamicArray := nil 就行了。
6> 虽然动态数组实际是一个指针,但使用数组时却不能用 DynamicArray^ 的形式来访问数组元素或者
用 New/Dispose 的指针分配和释放操作来重新分配或释放一个动态数组。
(这一点倒和类相似,Delphi 中所有类都是引用(或者说都是指针),但却不能用 TStrings^ 的形式来
使用类,或许这里面有什么联系吧,呵呵,猜测而已)
7> 对于字串型动态数组,同样遵循变量引用计数规则(与 AnsiString 一致)。
...
<以上是我的一些理解,不要嫌罗索哦。如果有不妥或者错误,望请指正和补充。占用篇幅,在此表示歉意>
下面是我的测试代码(呵呵,这一次可是真正测试过了):
library DynArr;
uses
ShareMem, //引用 ShareMem 主要是保证传递长字符串时同样有效及
//允许 Delphi 统一管理 APP 及 DLL 中的内存分配/释放
//因为在常规 DLL中,有一句经典的话:
// 不要在 DLL 外部释放 DLL 中分配的内存
//Delphi能够绕开这一点,或许是借助于 VMT 吧(具体也不清楚)
Windows,
SysUtils,
Classes;
{$R *.RES}
type
TStringArray = array of string;
procedure GetDynArrItems(var Arr: TStringArray); stdcall;
const
MAX_ARRAY_SIZE = 100;
var
I: Longint;
begin
SetLength(Arr, MAX_ARRAY_SIZE);
for I := 0 to MAX_ARRAY_SIZE - 1 do
Arr := Format('Dlls Alloc Item %d', );
end;
exports
GetDynArrItems;
begin
end.
------------------------------------------------------------------------------
program Demo;
uses
ShareMem, //引用 ShareMem,与 DLL 一致
Forms,
DemoFrm in 'DemoFrm.pas' {Form1};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
unit DemoFrm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
type
TStringArray = array of string;
procedure GetDynArrItems(var Arr: TStringArray); stdcall; external 'DynArr.dll';
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
Arr: TStringArray;
I: Longint;
begin
GetDynArrItems(Arr);
ListBox1.Items.Clear
for I := Low(Arr) to High(Arr) do
ListBox1.Items.Add(Arr);
end;
end.