Первоначально у меня был массив [1..1000], который был определен как глобальная переменная. Но теперь мне нужно, чтобы это было n, а не 1000, и я не узнаю n до более позднего времени. Я знаю, что n до того, как я заполнил массив, но мне нужно, чтобы он был глобальным, поэтому вам нужно определить размер глобального массива во время выполнения.
Контекст заполняет массив линейным преобразованием байтов в файле. Я не знаю, насколько велик файл, пока кто-то не захочет его открыть, и файлы могут быть любого размера.
Как и в 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 лет.
Во-первых, здесь общий ответ на первую часть вашего вопроса:
Если ваш массив больше не является статическим, вам может потребоваться использовать TList, TStringList или один из многих классов контейнеров в модуле Contnrs.
Они могут лучше представлять, что вы делаете, предоставлять дополнительные возможности, которые могут вам понадобиться, например. сортировки или пары имени/значения, они динамически растут по мере необходимости и очень хорошо оптимизированы.
Тогда вы сказали:
"Контекст заполняет массив линейным преобразованием байтов в файле. Я не знаю, насколько велик файл, пока кто-то не захочет его открыть, и файлы могут быть любого размера".
Для вашей конкретной проблемы я буду загружать байты в файл, используя:
MyFileStream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite); Size := MyFileStream.Size - MyFileStream.Position; SetLength(Buffer, Size); MyFileStream.Read(Buffer[0], Size);
Затем вы можете легко использовать указатель PChar для прохождения каждого символа или даже каждого байта в буфере один за другим и преобразовать их так, как вам нужно.