Шаблон массива переменной длины
Автор: Ed Jordan
Может ли кто мне подсказать как динамически создать массив записей и получить доступ к отдельным элементам?
Определите тип массива, которым может содержать максимальное количество записей, затем определите тип, являющийся указателем на массив. Идея заключается в том, чтобы не создавать экземпляр самого большого массива; а вместо этого использовать указательный тип и GetMem для распределения памяти для необходимого вам количества записей.
Я разработал то, что я называю шаблоном массива переменной длины "для бедных людей"...
unit %s;
{ -----------------------------------------------------------
ШАБЛОН МАССИВА ПЕРЕМЕННОЙ ДЛИНЫ
Вы можете использовать этот шаблон для создания массива
переменной длины любого типа данных.
Для того, чтобы превратить шаблон с модуль, прогоните его
через текстовый процессор, выполните во всем файле операцию
поиска/замены для замены знака процента на ваш тип данных.
----------------------------------------------------------- }
interface
const
%MaxCapacity = High(Cardinal) div SizeOf(%);
type
T%Index = 0..%MaxCapacity - 1;
T%s = array[T%Index] of %;
P%s = ^T%s;
function %sSize(Capacity: T%Index): Cardinal;
function Get%s(Capacity: T%Index): P%s;
function Resize%s(var P: P%s;
OldCapacity, NewCapacity: T%Index): P%s;
procedure Free%s(var P: P%s; Capacity: T%Index);
implementation
uses SysUtils;
function %sSize(Capacity: T%Index): Cardinal;
begin
Result := Capacity * SizeOf(%);
end;
function Get%s(Capacity: T%Index): P%s;
begin
GetMem(Result, %sSize(Capacity));
end;
function Resize%s(var P: P%s;
OldCapacity, NewCapacity: T%Index): P%s;
begin
ReAllocMem(P, %sSize(OldCapacity), %sSize(NewCapacity));
end;
procedure Free%s(var P: P%s; Capacity: T%Index);
begin
FreeMem(P, %sSize(Capacity));
P := nil;
end;
end.
|
Приведенный выше модуль определяет тип массива и тип-указатель на массив,
далее я приведу четыре полезные подпрограммы для работы с ним.
Вот модуль, использующий после операции поиска и замены (см. выше) тип записи
'MyRecord', содержащий также определение этой записи. Поскольку "MyRecords" было
очень длинным для имени модуля, я укоротил его. Имейте в виду, что PMyRecords -
тип вашего переменного массива, если вы используете этот модуль.
unit MyRecs;
interface
type
MyRecord = record
AnInt: Integer;
AString: string[10];
end;
const
MyRecordMaxCapacity = High(Cardinal) div SizeOf(MyRecord);
type
TMyRecordIndex = 0..MyRecordMaxCapacity - 1;
TMyRecords = array[TMyRecordIndex] of MyRecord;
PMyRecords = ^TMyRecords;
function MyRecordsSize(Capacity: TMyRecordIndex): Cardinal;
function GetMyRecords(Capacity: TMyRecordIndex): PMyRecords;
function ResizeMyRecords(var P: PMyRecords;
OldCapacity, NewCapacity: TMyRecordIndex): PMyRecords;
procedure FreeMyRecords(var P: PMyRecords; Capacity: TMyRecordIndex);
implementation
uses SysUtils;
function MyRecordsSize(Capacity: TMyRecordIndex): Cardinal;
begin
Result := Capacity * SizeOf(MyRecord);
end;
function GetMyRecords(Capacity: TMyRecordIndex): PMyRecords;
begin
GetMem(Result, MyRecordsSize(Capacity));
end;
function ResizeMyRecords(var P: PMyRecords;
OldCapacity, NewCapacity: TMyRecordIndex): PMyRecords;
begin
ReAllocMem(P, MyRecordsSize(OldCapacity),
MyRecordsSize(NewCapacity));
end;
procedure FreeMyRecords(var P: PMyRecords; Capacity: TMyRecordIndex);
begin
FreeMem(P, MyRecordsSize(Capacity));
P := nil;
end;
end.
|
Наконец, вот пример использования массива переменной длины. Помните, что
указатель должен использоваться с символом "^"...
procedure TForm1.Button1Click( Sender: TObject );
var
P: PMyRecords;
begin
P := GetMyRecords( 10 );
try
P^[ 0 ].AnInt := 2001;
P^[ 0 ].AString := 'Космическая одиссея';
finally
FreeMyRecords( P, 10 );
end;
end;
|
|