Идёт загрузка страницы...

htp://aptem.net.ru





Шаблон массива переменной длины

Может ли кто мне подсказать как динамически создать массив записей и получить доступ к отдельным элементам?

Определите тип массива, которым может содержать максимальное количество записей, затем определите тип, являющийся указателем на массив. Идея заключается в том, чтобы не создавать экземпляр самого большого массива; а вместо этого использовать указательный тип и 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;

- Ed Jordan [000990]