delphi - constant - ¿Cómo declaro una matriz cuando no sé la longitud hasta el tiempo de ejecución?
delphi var array (2)
Originalmente tenía una matriz [1..1000] que se definió como una variable global. Pero ahora necesito que sea n, no 1000 y no lo sé hasta más tarde. Sé lo que es antes de llenar el conjunto, pero necesito que sea global, por lo tanto, necesito una forma de definir el tamaño de un conjunto global en tiempo de ejecución.
El contexto está llenando una matriz con una transformación lineal de los bytes en un archivo. No sé cuán grande es el archivo hasta que alguien quiera abrirlo y los archivos pueden ser de cualquier tamaño.
A partir de Delphi 4, Delphi admite matrices dinámicas . Puede modificar sus tamaños en tiempo de ejecución y retendrán los datos almacenados en otros elementos en el tamaño anterior. Pueden contener elementos de cualquier tipo homogéneo, incluidos registros y otras matrices. Puede declarar una matriz dinámica igual que declara matrices "estáticas" normales, pero simplemente omita los límites de la matriz:
var
ArthurArray: array of TForm;
Aunque las matrices estáticas le permiten especificar tanto el límite inferior como el superior, el índice bajo de un conjunto dinámico es siempre cero. El índice alto está dado por la función High
, que siempre devuelve uno menos que la longitud de la matriz. Para cualquier arreglo dinámico x
, High(x) = Length(x)-1
.
Se puede acceder a una variable global mediante cualquier código, incluidos los procedimientos locales.
Una variable global del tipo de matriz dinámica se inicializará para que sea una matriz vacía . Su longitud será cero y High
invocó a esa matriz será -1. Low
en esa matriz todavía regresará a cero.
En cualquier momento, puede cambiar el tamaño de una matriz dinámica. Use la función SetLength
, tal como lo puede hacer con las cadenas:
var
NumElements: Integer;
begin
NumElements := GetNumberOfArthurForms();
SetLength(ArthurArray, NumElements);
end;
Si tiene una matriz multidimensional, puede establecer sus longitudes en un bucle:
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;
Hay un atajo para configurar las longitudes de todos los arreglos internos a la vez:
begin
SetLength(matrix, height, width);
end;
Como mencioné, las matrices dinámicas conservan sus valores anteriores cuando los cambias de tamaño:
var
data: array of string;
begin
SetLength(data, 2);
data[1] := ''foo'';
SetLength(data, 20);
Assert(data[1] = ''foo'');
end;
Pero si acorta la matriz, cualquier elemento que haya residido más allá del último elemento desaparecerá para siempre:
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;
Mis demostraciones anteriores usaron cadenas. Las cadenas son especiales en Delphi; son administrados por el compilador a través de recuentos de referencia. Debido a eso, los nuevos elementos de matriz dinámica de tipo cadena se inicializan para estar vacíos. Pero si hubiera usado enteros en su lugar, no habría garantía de los valores de los nuevos elementos. Pueden ser cero, pero también pueden ser cualquier cosa, al igual que los valores iniciales de las variables locales independientes.
Los archivos de ayuda de Delphi 7 son muy buenos, según me han dicho. Por favor, lea más acerca de las matrices dinámicas allí. Puede encontrar demostraciones de su uso a través del código fuente VCL y RTL proporcionado en su instalación Delphi, así como en casi cualquier ejemplo de código Delphi producido en los últimos 10 años.
Primero, aquí hay una respuesta general a la primera parte de su pregunta:
Si su matriz ya no es estática, es posible que desee considerar el uso de un TList, una TStringList o una de las muchas clases de contenedor en la unidad Contnrs.
Pueden representar mejor lo que estás haciendo, proporcionar las capacidades adicionales que podrías necesitar, por ejemplo, clasificación o pares de nombre / valor, crecen dinámicamente a medida que los necesitas y se han optimizado muy bien.
Entonces dijiste:
"El contexto está llenando una matriz con una transformación lineal de los bytes en un archivo. No sé cuán grande es el archivo hasta que alguien quiera abrirlo y los archivos pueden ser de cualquier tamaño".
Para su problema específico, cargaría los bytes en un archivo usando:
MyFileStream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite); Size := MyFileStream.Size - MyFileStream.Position; SetLength(Buffer, Size); MyFileStream.Read(Buffer[0], Size);
Luego puede usar fácilmente un puntero de PChar para revisar cada carácter o incluso cada byte en el Buffer uno por uno y transformarlos de la manera que lo necesite.