Q: Is there any way to dynamically redimension an array?
A: When you dynamically allocate space for an array, you *can* dynamically allocate the size as needed. e.g.
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.
FWIW, 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:
time for my canned reply re. dynamic arrays:
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