Beranda > Delphi > Dynamic Array Sizing (old style)

Dynamic Array Sizing (old style)

Is there any way to dynamically redimension an array? When you dynamically allocate space for an array, you *can* dynamically allocate the size as needed.


type
TIntegerArray = array[0..32767] of integer;
{Types don't allocate memory}
PIntegerArray = ^TIntegerArray;
var
I1,I2 : PIntegerArray;
begin
GetMem(I1,500*SizeOf(Integer));
{I1 now points to a 500 element array}
GetMem(I2,1000*SizeOf(Integer));
{I2 now points to a 1000 element array}
...

Ok, now *THIS* kind of variable-sized array has been available in Pascal for many a long year. That is, the kind where you decide the size at run-time but don't change it. Here is an example that works with records:  E.g.

TYPE
VarArray = Array[0..65520 DIV SizeOf(MyRecord)] OF
MyRecord;
ptrVarArray = ^VarArray;
VAR
MyArray : ptrVarArray;
GetMem(MyArray, NumNeeded*SizeOf(MyRecord));

See? You define an array TYPE as large as possible, given the almost-64k limit on the size of a single variable. You define a pointer to that type. And you allocate just enough memory to hold the actual number needed. You can definitely use a TList too, but you'll need to define a simple OBJECT that holds your variant record, because TLists only hold TObjects and their descendants.

Here is a later post on C-Serve: ReAllocMem comes closest. You allocate your array on the heap with some incantations like

Type
TIntArray = Array [0..High(Word) div Sizeof(Integer)
-1] of Integer;
{declares the maximum size possible for an array
of Integers }
PIntArray = ^TIntArray;

Procedure AllocArray( Var pArr: PIntArray; items: Word;
Var maxIndex: Word);
Begin
If items > 0 Then Begin
GetMem( pArr, items * Sizeof( Integer ));
maxIndex := Pred( items );
End
Else
pArr := Nil;
End;

Procedure ReDimArray(Var pArr : PIntArray;
newItems: Word; Var maxIndex: Word);
Begin
If pArr = Nil Then
AllocArray( pArr, newItems, maxIndex )
Else Begin
ReAllocMem( pArr, Succ(maxIndex)*Sizeof(Integer),
newItems*Sizeof(Integer));
maxIndex := Pred( newItems );
End;
End;

Procedure DisposeArray( Var pArr: PIntArray;
maxIndex: Word );
Begin
FreeMem( pArr, Succ(maxIndex)*SizeOf(Integer));
End;

Var
pMyArray: PIntArray;
maxIndex, i: Word;

Begin
try
AllocArray( pMyArray, 100, maxIndex );
For i:= 0 To maxIndex Do pMyArray^[i] := i;
...
RedimArray( pMyArray, 200, maxIndex );
For i:= 0 To maxIndex div 2 Do
pMyArray^[Succ(maxIndex div 2)+i] :=
Sqr(pMyArray^[i]);
....
finally
DisposeArray( pMyArray, maxIndex );
end;
..

"YIKES" i hear you say, "do i have to do this kind of gyrations for each array type i might need???". Well, you could, but it is not very difficult to write a set of generic procedures that will work for every base type you might use for an array. We assume that the array type is always declared with a lower bound of 0 and also use Cardinal instead of Word so the procedures will automagically expand to handle > 64K arrays under Delphi32.

Procedure AllocArray( Var pArr: Pointer; items,
itemsize: Cardinal; Var maxIndex: Cardinal);
Begin
If items > 0 Then Begin
GetMem( pArr, items * itemsize);
maxIndex := Pred( items );
End
Else Begin
pArr := Nil;
maxIndex := 0;
{WARNING! This is still an invalid index here! }
End;
End;

Procedure ReDimArray( Var pArr: Pointer; newItems,
itemsize: Cardinal; Var maxIndex: Cardinal);
Begin
If pArr = Nil Then
AllocArray( pArr, newItems, itemsize, maxIndex )
Else Begin
ReAllocMem( pArr, Succ(maxIndex)*itemsize,
newItems*itemsize);
maxIndex := Pred( newItems );
End;
End;

Procedure DisposeArray( Var pArr: Pointer; itemsize,
maxIndex: Cardinal );
Begin
FreeMem( pArr, Succ(maxIndex)*itemsize);
End;

To use these procedures to make a dynamic array of Double, for example, you would proceed as follows:

type
{we can directly declare a pointer to an array, no need to declare the array first}
PDoubleArray = ^Array [0..High(Cardinal) div
Sizeof(Double) -1] of Double;
Var
pDbl: PDoubleArray;
maxIndex, i: Cardinal;
deg2arc: Double;

Begin
deg2arc := Pi/180.0;
try
AllocArray(pDbl, 360, Sizeof(Double), maxIndex);
For i:= 0 To maxIndex Do
pDbl^[i] := Sin( Float(i) * deg2arc );
ReDimArray(pDlb, 720, Sizeof(Double), maxIndex);

For i:= 360 To maxIndex Do
pDbl^[i] := Cos( Float(i-360) * deg2arc );
finally
DisposeArray( pDbl, Sizeof(Double), maxIndex );
end;

And now the final icing: all this was typed off forehead; no idea if it will even compile <eg>! And a safety net feature is still missing: AllocArray and RedimArray should raise an exception if you try to allocate an array > 64Kbyte under Delphi16. I left this out since i'm not really familiar with these beasties (exceptions) yet. Delphi may do it anyway if range checking is enabled.

Here is Peter Below's approach: You allocate your array on the heap with some incantations like

Type
TIntArray = Array [0..High(Word) div Sizeof(Integer)
-1] of Integer;
{declares the maximum size possible for an array
of Integers }
PIntArray = ^TIntArray;

Procedure AllocArray( Var pArr: PIntArray; items: Word;
Var maxIndex: Word);
Begin
If items > 0 Then Begin
GetMem( pArr, items * Sizeof( Integer ));
maxIndex := Pred( items );
End
Else
pArr := Nil;
End;

Procedure ReDimArray( Var pArr: PIntArray;
newItems: Word; Var maxIndex: Word );
Begin
If pArr = Nil Then
AllocArray( pArr, newItems, maxIndex )
Else Begin
ReAllocMem( pArr, Succ(maxIndex)*Sizeof(Integer),
newItems*Sizeof(Integer));
maxIndex := Pred( newItems );
End;
End;

Procedure DisposeArray( Var pArr: PIntArray;
maxIndex: Word );
Begin
FreeMem( pArr, Succ(maxIndex)*SizeOf(Integer));
End;

Var
pMyArray: PIntArray;
maxIndex, i: Word;

Begin
try
AllocArray( pMyArray, 100, maxIndex );
For i:= 0 To maxIndex Do pMyArray^[i] := i;
...
RedimArray( pMyArray, 200, maxIndex );
For i:= 0 To maxIndex div 2 Do
pMyArray^[Succ(maxIndex div 2)+i] :=
Sqr(pMyArray^[i]);
....
finally
end;

"YIKES" I hear you say, "do I have to do this kind of gyrations for each array type i might need???". Well, you could, but it is not very difficult to write a set of generic procedures that will work for every base type you might use for an array. We assume that the array type is always declared with a lower bound of 0 and also use Cardinal instead of Word so the procedures will automagically expand to handle > 64K arrays under Delphi32.

Procedure AllocArray( Var pArr: Pointer; items,
itemsize): Card

Iklan
Kategori:Delphi
  1. Belum ada komentar.
  1. No trackbacks yet.

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: