Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Шаблон массива переменной длины

Автор: 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;

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay