2016-04-06 18 views
1

getmemを使用して2D配列を作成するにはどうすればよいですか?私はCと同様のアプローチを試みたが、これは期待通りにコンパイルされないようだ。getmemを使用して2D配列を作成する

var 
    arr:PInteger; 
begin 
    getmem(arr, 5*5*sizeof(integer)); 
    arr[5]; //on this compiler produces error "Array type required" 
end; 

これは明示的にはgetmemを使用する解決策が必要な宿題割り当てタスクです。

+0

2D配列についてはお話ししますが、試行された逆参照では1つのインデックスしか表示されません。配列にインデックスを付けるには、いくつかの方法があります。細部が提供されずに何が最善であるかを知ることは難しい。これは宿題のようですが、あなたの仕事を詳細に話したことはありません。あなたはあなたの家庭教師に尋ねましたか? –

+0

@DevidHeffernanはい、それは大学での仕事です。 2D配列を作成し、getmemを使用して入力するだけです。私はそれがここにあったようにしようとしましたhttp://stackoverflow.com/questions/32957977/using-getmem-for-allocation-of-multidimensional-arrays – mobimore

+0

私はあなたがタスクのより詳細な説明を持っていると思っているでしょうか私たちよりも?次に何が起こるかは、私たちが何かを提案し、あなたが「ああ、私の仕事は私にそれをさせてくれません」と言うことです。それは私たちにとって楽しいものではありません。なぜあなたは自分の宿題をしませんか?あなたはこれをする方法を教えられた授業に行っていませんでしたか?あなたのテキストブックは何を言いますか?なぜあなたはポインタを配列として扱うことができると思いましたか?それは授業で教えられましたか?あなたは家庭教師に相談しましたか? –

答えて

1

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、
...等

ヨーヨー場合定義を

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] 

しかし、当然、これはひどく柔軟ではありません。コンパイル時に型の固定境界を定義する必要があります。これはあまり満足のいくものではありません。コンパイラは、実行時にインデックスを正しく計算できるように、十分に定義された次元サイズの型定義が必要です。したがって、一般的な場合には、多次元の動作を手動で実装する必要があります(線形インデックス変換を使用)。

これは、デルファイでは賢明な方法ではありません。私はこれが学校の課題だと理解していますが、CプログラマのようにDelphiコースを教えるような感じです。このようなやり方でこの種のことをしたいのであれば、Delphiは本当に適切なものではないと思います。 Delphiの新しいバージョンでは、より柔軟な(POINTERMATH)がありますが、このスタイルのプログラミングのユースケースは非常に限られていると考えられます。

+0

2D配列の場合、実行時に2つのインデックスから線形インデックスに変換する必要があります。 'LinearIndex:= iRow * nCol + iCol'のコードです。 –

+0

@DavidHeffernanこれは代替ですが、実際の2Dインデックス作成の動作を生成しません。問題は、2D配列について質問していました。これは、 'p^[i、j]'のようにインデックスを作成することを意味しています。 –

+0

コンパイル時に最も外側の次元を除くすべてのサイズがわかっていなければ、これは不可能です。つまり、手動によるインデックス作成が必要です。実行時にのみ認識されるサイズを持つ多次元配列をサポートする言語は多くありません。 Fortranが最も重要な例です。 –

関連する問題