Delphi数组初始化

时间:2013-06-17 17:58:39

标签: delphi delphi-xe3

这有点延续了我之前的问题,found here.本质上,我试图用一个基本的例子来测试dll /函数,但是我得到了' E2010 - 不兼容的类型:AInteger / ADouble和Set '和' E1012 - 常量表达式违反了我的数组上的子范围'错误。我(有点)得到它想说的,但无法弄清楚我应该修复什么。例如:

var
  n: Integer; 
  Ap, Ai: AInteger;
  Ax, b: ADouble;

begin
  // Initializations
  n := 5;
  Ap := [0, 2, 5, 9, 10, 12]; <- E2010
  Ai := [0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4]; <- E2010
  Ax := [2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1]; <- E2010 and E1012
  b := [8, 45, -3, 3, 19]; <- E1012

AIntegerADouble类型是我的数组:

ADouble = array[0..High(Integer) div SizeOf(Double) - 1] of Double;
AInteger = array[0..High(Integer) div SizeOf(Integer) - 1] of Integer;

并且应该以这种方式初始化(​​根据Rudy的Delphi页面和其他C-to-Pascal源代码),因为它们在C中写为double Ax[]。我确信有一些简单的我做错了或者可以为了测试我的dll而改变,但也许我谷歌搜索错误,因为我找不到一个示例/解决方案。所以,问题形式:

Q1 :E1012是指

  

“如果你做这些事情 [AInteger和ADouble] ,请务必不要太靠近   高(整数),因为编译器可能会抱怨数据   结构太大了。“(引自Rudy的页面)

Q2 :我该如何更改此代码?

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:8)

你可以用这样的语法来做到这一点。

如此定义数组:

ADouble = array[0..High(Integer) div SizeOf(Double) - 1] of Double;

将初始化整个32位RAM大小的整数数组!您永远无法分配这样的变量(仅在Win64上,但您将使用4 GB的RAM仅存储6个整数)! :)

您的阵列需要动态,即在运行时更改大小。所以你必须这样定义:

type
  AInteger =  array of integer;

此类数组无法在语言的当前状态AFAIR中直接分配。

所以你需要编写这样一个函数:

procedure SetArray(var dest: AInteger; const values: array of integer);
begin
  SetLength(dest,Length(values));
  move(values[0],dest[0],length(values)*sizeof(integer));
end;

您可以使用常量数组作为源:

const
  C: array[0..5] of Integer = (0, 2, 5, 9, 10, 12);
var
  Ap: AInteger;
begin
  SetArray(Ap,C);

或使用开放数组参数

var
  Ai: AInteger;
begin
  SetArray(Ai,[0, 2, 5, 9, 10, 12]);

当然,第二种解决方案听起来更接近您的期望。

更新:对于较新版本,您当然可以使用动态数组构造函数,如下所示:

var
  Ai: AInteger;
begin
  Ai := AInteger.Create(0,2,5,9,10,12);

答案 1 :(得分:2)

在我看来,好像你有用C编写的稀疏求解器代码,并试图将它链接到你的Delphi程序。我认为你宣布外部进口的方式存在根本问题。我没有回答您直接提出的问题,而是向您展示我认为是宣布和调用此类外部进口的正确方式。

我要说的第一件事是你声明的大型静态数组类型不是你需要的。这些数组类型有时可能很有用,但只有在将另一个数组转换为PADouble = ^ADouble时才有用。在您的情况下,您根本不需要这些数组,我建议您删除它们。

我将假设你正在调用一个名为solve的函数,该函数需要nnzApAi,{{1 }和Ax作为输入参数,并返回b作为输出参数。函数返回xx其中A*x=b是由An和{{1}指定的Ap维方形稀疏矩阵}。 Ai参数指定非零元素的数量。毫无疑问,实际功能的细节会有所不同,但概念也是一样的。例如,从Ax推断nz是很常见的,但这些细节供您解决。

我建议你声明函数接收参数作为第一个元素的指针。所以函数声明如下所示:

nz

然后你需要填充你的稀疏矩阵数组。将这些声明为动态数组:

Ap[n]

我希望您在运行时只知道function solve( n: Integer; nz: Integer; Ap: PInteger; Ai: PInteger; Ax: PDouble; b: PDouble; x: PDouble ): Integer; cdecl; external; var Ap: TArray<Integer>; Ai: TArray<Integer>; Ax: TArray<Double>; .... SetLength(Ap, n); Ap[0] := ...; .... SetLength(Ai, nz); Ap[0] := ...; .... SetLength(Ax, nz); Ax[0] := ...; .... 等的值,并且使用循环等填充矩阵的内容。问题中的代码可能是测试代码,用于尝试测试外部代码。 Arnaud的回答为您提供了有关如何填充动态数组的合理建议。

您还需要初始化nnz

b

现在您可以调用该函数:

x

最后一点,转换使用通用数组。由于您使用的是现代Delphi,我建议您使用通用动态数组。因此,您应该使用var b: TArray<Double>; x: TArray<Double>; .... SetLength(b, n); b[0] := ...; .... SetLength(x, n); // no need to initialise values of x[i] since it is the output 而不是var retval: Integer; .... retval := solve(n, nz, PInteger(Ap), PInteger(Ai), PDouble(Ax), PDouble(b), PDouble(x)); 。原因是泛型类型与旧式动态数组具有不同的类型兼容性规则。例如,在上面的代码中,array of ...TArray<...>是分配兼容的。但如果他们被宣布为这样:

b

然后他们不会兼容任务。您可以通过声明类型x来解决该问题。但是,如果使用泛型数组,则可以使用通用容器类(如var b: array of Double; x: array of Double; ),而不是返回类型TDoubleArray = array of Double的值,这些值很容易消耗。

我知道这不是你提出的问题,但我觉得它可能对你有用。

答案 2 :(得分:0)

此问题与开放数组无关,因此请从您的问题中删除该标记。

您正在使用的括号语法声明Set个值,这基本上是一种特殊类型的位掩码,其中每个位对应于该位置的值。换句话说,[0, 2, 5, 9, 10, 12]是包含6个元素的Set of Integer,其中位0指的是值0,位1指的是值2,位2指的是值5,依此类推。无法像您尝试的那样将Set直接分配给数组。