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

28

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

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

  • 0
    и на каком языке это точно?
  • 2
    Конструкция [lobound..hibound] для определения массивов в сочетании с глобальными массивами и файловым вводом-выводом оставляет только Pascal и Ada в соревновании, поэтому ставки были бы на Delphi :) Роб, однако, сделал тэг после вашего комментария.
Теги:
arrays
global-variables
dynamic-arrays

2 ответа

85
Лучший ответ

Как и в 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 лет.

  • 1
    +1, очень полный ответ. Впечатляет. Теперь, пожалуйста, кто-нибудь отредактирует резюме вопроса, включив в него «Delphi» и «динамические массивы», чтобы люди могли найти его в результатах поиска.
  • 0
    ВАУ все, что мне нужно знать, большое спасибо, Удивительный ответ!
Показать ещё 4 комментария
1

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

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

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


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

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

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню