Come posso dichiarare un array quando non conosco la lunghezza fino al runtime?

Originariamente avevo un array [1..1000] che era definito come una variabile globale. Ma ora ho bisogno che sia n, non 1000 e non ne scopro n più tardi. So che cosa è prima di riempire l’array ma ho bisogno che sia globale, quindi ho bisogno di un modo per definire la dimensione di un array globale in fase di esecuzione.

Il contesto sta riempiendo una matrice con una trasformazione lineare dei byte in un file. Non so quanto è grande il file fino a quando qualcuno non vuole aprirlo e i file possono essere di qualsiasi dimensione.

A partire da Delphi 4, Delphi supporta gli array dinamici . È ansible modificare le dimensioni in fase di esecuzione e manterranno i dati archiviati in altri elementi con le dimensioni precedenti. Possono contenere elementi di qualsiasi tipo omogeneo, inclusi record e altri array. Puoi dichiarare un array dinamico come se dichiarassi array normali, “statici”, ma semplicemente ometti i limiti dell’array:

var ArthurArray: array of TForm; 

Sebbene gli array statici consentano di specificare sia il limite inferiore che quello superiore, l’indice basso di un array dinamico è sempre zero. L’indice alto è dato dalla funzione High , che restituisce sempre uno in meno della lunghezza dell’array. Per qualsiasi array dinamico x , High(x) = Length(x)-1 .

È ansible accedere a una variabile globale da qualsiasi codice, incluse le procedure locali.

Una variabile globale di tipo array dinamico verrà inizializzata per essere una matrice vuota . La sua lunghezza sarà pari a zero e High chiamato quella matrice sarà -1. Low su quella matrice restituirà ancora zero.

In qualsiasi momento, è ansible ridimensionare un array dinamico. Usa la funzione SetLength , proprio come puoi fare con le stringhe:

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

Se si dispone di un array multidimensionale, è ansible impostare le loro lunghezze in un ciclo:

 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; 

C’è una scorciatoia per questo per impostare le lunghezze di tutti gli array interni contemporaneamente:

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

Come ho già detto, gli array dinamici mantengono i loro vecchi valori quando li ridimensionate:

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

Ma se accorgi la matrice, tutti gli elementi che risiedono oltre il nuovo ultimo elemento sono andati per sempre:

 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; 

Le mie dimostrazioni hanno usato le stringhe sopra. Le stringhe sono speciali in Delphi; sono gestiti dal compilatore attraverso i conteggi dei riferimenti. Per questo motivo, i nuovi elementi di matrice dynamic della stringa di tipo vengono inizializzati per essere vuoti. Ma se avessi usato gli interi invece, non ci sarebbe alcuna garanzia dei valori dei nuovi elementi. Potrebbero essere zero, ma potrebbero anche essere qualsiasi altra cosa, proprio come i valori iniziali delle variabili locali indipendenti.

I file della guida di Delphi 7 sono molto buoni, mi hanno detto. Si prega di leggere di più sugli array dinamici lì. Puoi trovare dimostrazioni del loro utilizzo in tutto il codice sorgente VCL e RTL fornito nell’installazione Delphi, così come in quasi tutti gli esempi di codice Delphi prodotti negli ultimi 10 anni.

Innanzitutto, ecco una risposta generale alla prima parte della tua domanda:

Se l’array non è più statico, è ansible prendere in considerazione l’utilizzo di un TList, di una TStringList o di una delle numerose classi contenitore nell’unità Contnrs.

Possono rappresentare meglio ciò che stai facendo, fornire funzionalità aggiuntive che potresti avere bisogno, ad esempio l’ordinamento o le coppie nome / valore, crescono dynamicmente quando ne hai bisogno e sono state ottimizzate molto bene.


Allora hai detto:

“Il contesto sta riempiendo un array con una trasformazione lineare dei byte in un file. Non so quanto sia grande il file finché qualcuno non lo vuole aprire e i file possono essere di qualsiasi dimensione.”

Per il tuo problema specifico, vorrei caricare i byte in un file usando:

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

Quindi è ansible utilizzare facilmente un puntatore PChar per passare attraverso ciascun carattere o anche ogni byte nel buffer uno per uno e trasformarli nel modo desiderato.