Подтвердить что ты не робот

Как объявить массив, когда я не знаю длину до времени выполнения?

Первоначально у меня был массив [1..1000], который был определен как глобальная переменная. Но теперь мне нужно, чтобы это было n, а не 1000, и я не узнаю n до более позднего времени. Я знаю, что n до того, как я заполнил массив, но мне нужно, чтобы он был глобальным, поэтому вам нужно определить размер глобального массива во время выполнения.

Контекст заполняет массив линейным преобразованием байтов в файле. Я не знаю, насколько велик файл, пока кто-то не захочет его открыть, и файлы могут быть любого размера.

4b9b3361

Ответ 1

Как и в Delphi 4, Delphi поддерживает динамические массивы . Вы можете изменить их размеры во время выполнения, и они сохранят данные, которые вы сохранили в других элементах старого размера. Они могут содержать элементы любого однородного типа, включая записи и другие массивы. Вы можете объявить динамический массив так же, как вы объявляете обычные, "статические" массивы, но просто опустите границы массива:

var
  ArthurArray: array of TForm;

Хотя статические массивы позволяют указать как нижнюю, так и верхнюю границу, низкий индекс динамического массива всегда равен нулю. Высокий индекс задается функцией High, которая всегда возвращает на единицу меньше длины массива. Для любого динамического массива x, High(x) = Length(x)-1.

Доступ к глобальной переменной можно получить с помощью любого кода, включая локальные процедуры.

Глобальная переменная типа dynamic-array будет инициализирована как пустой массив. Его длина будет равна нулю, а High вызывается, что этот массив будет равен -1. Low в этом массиве все равно будет возвращать ноль.

В любое время вы можете изменить размер динамического массива. Используйте функцию SetLength так же, как вы можете сделать со строками:

var
  NumElements: Integer;
begin
  NumElements := GetNumberOfArthurForms();
  SetLength(ArthurArray, NumElements);
end;

Если у вас многомерный массив, вы можете установить их длину в цикле:

var
  matrix: array of array of Double;
  i: Integer;
begin
  SetLength(matrix, height);
  for i := 0 to height - 1 do
    SetLength(matrix[i], width);
end;

Здесь есть ярлык для установки длин всех внутренних массивов сразу:

begin
  SetLength(matrix, height, width);
end;

Как я уже упоминал, динамические массивы сохраняют свои старые значения при их изменении:

var
  data: array of string;
begin
  SetLength(data, 2);
  data[1] := 'foo';
  SetLength(data, 20);
  Assert(data[1] = 'foo');
end;

Но если вы сократите массив, все элементы, которые были за пределами нового последнего элемента, исчезнут навсегда:

begin
  SetLength(data, 20);
  data[15] := 'foo';
  SetLength(data, 2);
  // data[15] does not exist anymore.
  SetLength(data, 16);
  writeln(data[15); // Should print an *empty* line.
end;

Мои демонстрации выше использованных строк. Строки являются специальными в Delphi; они управляются компилятором посредством подсчета ссылок. Из-за этого новые элементы динамического массива строки типа инициализируются пустым. Но если бы я использовал целые числа вместо этого, не было бы гарантии значений новых элементов. Они могут быть равны нулю, но они могут быть чем-то другим, также как и начальные значения автономных локальных переменных.

Файлы справки Delphi 7 очень хорошие, мне говорят. Читайте больше о динамических массивах. Вы можете найти демонстрации их использования во всем исходном коде VCL и RTL, предоставленном в вашей установке Delphi, а также почти в любом примере кода Delphi, выпущенном за последние 10 лет.

Ответ 2

Во-первых, здесь общий ответ на первую часть вашего вопроса:

Если ваш массив больше не является статическим, вам может потребоваться использовать TList, TStringList или один из многих классов контейнеров в модуле Contnrs.

Они могут лучше представлять, что вы делаете, предоставлять дополнительные возможности, которые могут вам понадобиться, например. сортировки или пары имени/значения, они динамически растут по мере необходимости и очень хорошо оптимизированы.


Тогда вы сказали:

"Контекст заполняет массив линейным преобразованием байтов в файле. Я не знаю, насколько велик файл, пока кто-то не захочет его открыть, и файлы могут быть любого размера".

Для вашей конкретной проблемы я буду загружать байты в файл, используя:

  MyFileStream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
  Size := MyFileStream.Size - MyFileStream.Position;
  SetLength(Buffer, Size);
  MyFileStream.Read(Buffer[0], Size);

Затем вы можете легко использовать указатель PChar для прохождения каждого символа или даже каждого байта в буфере один за другим и преобразовать их так, как вам нужно.