如何使用getmem创建2D数组?我尝试了一种类似于C语言的方法,但似乎不能像预期的那样编译。
var
arr:PInteger;
begin
getmem(arr, 5*5*sizeof(integer));
arr[5]; //on this compiler produces error "Array type required"
end; 这是一个明确要求仅使用getmem的解决方案的家庭作业任务。
发布于 2016-04-06 19:54:35
正如David在评论中指出的那样,如果没有POINTERMATH支持,您实际上只能做这样的事情。
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TIntArray = array [0..0] of integer;
PIntArray = ^TIntArray;
var
p : PIntArray;
i : integer;
begin
GetMem(p, 5*5*SizeOf(integer));
for i := 0 to 24 do p^[i] := i;
for i := 0 to 24 do
WriteLn(Format('i=%d, value = %d', [i,p^[i]]));
ReadLn;
FreeMem(p);
end.然而,问题是关于2D数组的,所以我们可以假设您想要2D索引行为。您可能会认为可以这样扩展上面的内容:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
T2DIntArray = array [0..0, 0..0] of integer;
P2DIntArray = ^T2DIntArray;
var
p2d : P2DIntArray;
i, j : integer;
begin
GetMem(p2d, 5*5*SizeOf(integer));
for i := 0 to 4 do
for j := 0 to 4 do p2d^[i,j] := i*j;
for i := 0 to 4 do
for j := 0 to 4 do
WriteLn(Format('i=%d, j=%d, value = %d', [i,j,p2d^[i,j]]));
ReadLn;
FreeMem(p2d);
end.但这会产生无意义的结果。从编译后的程序集中,可以很容易地看到发生了什么:
Project1.dpr.16: for i := 0 to 4 do
0041A522 33C0 xor eax,eax
0041A524 A3CC1E4200 mov [$00421ecc],eax
Project1.dpr.17: for j := 0 to 4 do p2d^[i,j] := i*j;
0041A529 33C0 xor eax,eax
0041A52B A3D01E4200 mov [$00421ed0],eax
0041A530 A1CC1E4200 mov eax,[$00421ecc] // load i into EAX
0041A535 F72DD01E4200 imul dword ptr [$00421ed0]// EAX = i*j
0041A53B 8B15C81E4200 mov edx,[$00421ec8] // load p2d into EDX
0041A541 8B0DCC1E4200 mov ecx,[$00421ecc] // load i into ECX
0041A547 8D148A lea edx,[edx+ecx*4] // offset p2d by i*SizeOf(integer)
0041A54A 8B0DD01E4200 mov ecx,[$00421ed0] // load j into ECX
0041A550 89048A mov [edx+ecx*4],eax // move i*j to EDX + j*sizeOf(integer)
0041A553 FF05D01E4200 inc dword ptr [$00421ed0]
0041A559 833DD01E420005 cmp dword ptr [$00421ed0],$05
0041A560 75CE jnz $0041a530
0041A562 FF05CC1E4200 inc dword ptr [$00421ecc]很明显,这是行不通的--编译器希望第一个维度有单位大小,所以你最终会建立索引
0、1、2、3、4
1,2,3,4,5,
2,3,4,5,6,
...etc
如果将定义更改为
type
T2DIntArray = array [0..4, 0..4] of integer;
P2DIntArray = ^T2DIntArray; 然后一切都会按预期进行。
Project1.dpr.16: for i := 0 to 4 do
0041A522 33C0 xor eax,eax
0041A524 A3CC1E4200 mov [$00421ecc],eax
Project1.dpr.17: for j := 0 to 4 do p2d^[i,j] := i*j;
0041A529 33C0 xor eax,eax
0041A52B A3D01E4200 mov [$00421ed0],eax
0041A530 A1CC1E4200 mov eax,[$00421ecc]
0041A535 8D0480 lea eax,[eax+eax*4] // this is more like it
0041A538 8B15C81E4200 mov edx,[$00421ec8]
0041A53E 8D0482 lea eax,[edx+eax*4] // and this..
0041A541 8B15D01E4200 mov edx,[$00421ed0]
0041A547 8B0DCC1E4200 mov ecx,[$00421ecc]
0041A54D 0FAF0DD01E4200 imul ecx,[$00421ed0]
0041A554 890C90 mov [eax+edx*4],ecx // so we get what we want
0041A557 FF05D01E4200 inc dword ptr [$00421ed0]
0041A55D 833DD01E420005 cmp dword ptr [$00421ed0],$05
0041A564 75CA jnz $0041a530
0041A566 FF05CC1E4200 inc dword ptr [$00421ecc]但是,很自然,这并不是非常灵活。你必须在编译时为类型定义一个固定的边界,这不是很令人满意。编译器需要具有定义良好的维度大小的类型定义,以便能够在运行时正确计算索引。因此,在任何一般情况下,多维行为都必须手动实现(使用线性索引转换)。
所有这些都不是用Delphi做事情的明智方式。我知道这是学校的作业,但感觉有点像C程序员在教Delphi课程。如果你想以这种方式做这类事情,我不认为Delphi真的是合适的选择。在较新版本的Delphi中,您有更多的灵活性(使用POINTERMATH),但即使这样,这种编程风格的用例也必须被认为是极其有限的。
https://stackoverflow.com/questions/36446515
复制相似问题