Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: cappe - Marzo 08, 2025, 06:13:11 pm

Titolo: Inizializzazione array di record
Inserito da: cappe - Marzo 08, 2025, 06:13:11 pm
Ciao,
  ho un lapsus
con

type
pippo = record
  a : integer;
  b: String;
end;
arrPippo = array of pippo;

var
  uu : arrPippo; 
begin
   // la domanda è come lo inizializzo
   uu := arrPippo.Create( ??????) ;    // <- e se voglio mettere un record pippo come lo scrivo?
end;

Grazie.
Titolo: Re:Inizializzazione array di record
Inserito da: Narciso - Marzo 09, 2025, 07:35:09 am
guarda un po'...

Codice: [Seleziona]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button2: TButton;

    procedure Button2Click(Sender: TObject);

  private

  type tpippo = record
  a:integer;
  b:string[20];
  end;
  Var A_pippo:array of tpippo;

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }


procedure TForm1.Button2Click(Sender: TObject);
var x:integer;
begin

  setlength(a_pippo,0);
  for x:=0 to 9 do begin
  setlength(a_pippo,x+1);
  a_pippo[x].a:=x;
  a_pippo[x].b:=inttostr(x);

  end;
  showmessage(inttostr(length(A_pippo)));
end;

end.     
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 09, 2025, 11:03:33 am
guarda un po'...

Codice: [Seleziona]
  setlength(a_pippo,0);
  for x:=0 to 9 do begin
  setlength(a_pippo,x+1);
  a_pippo[x].a:=x;
  a_pippo[x].b:=inttostr(x);

  end;
 

Grazie per aver risposto.
Lo so che si più fare così, ma io volevo la forma ridotta con il .create
cioè dovrebbe essere qualcosa del tipo

uu := arrPippo.Create((1,'ww') ;

ma non mi ricordo (se si può fare) come.
Titolo: Re:Inizializzazione array di record
Inserito da: DragoRosso - Marzo 09, 2025, 01:35:31 pm
Puoi usare gli "advanced record" e creare delle procedure.
Comunque il costruttore di un record NON può avere parametri, procedure e metodi si.

Puoi quindi creare una procedura ad esempio Init( ....; ...) con cui inizializzi quello che vuoi.

I record non hanno distruttori !!!
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 09, 2025, 02:01:05 pm
Ma scusa se fosse un TStringArray io posso fare così

begin
arr := TStringArray.create('eee','rrr');
end;

e funziona, ma con un array di record?
Titolo: Re:Inizializzazione array di record
Inserito da: DragoRosso - Marzo 09, 2025, 03:00:14 pm
Ma scusa se fosse un TStringArray io posso fare così
begin
arr := TStringArray.create('eee','rrr');
end;
e funziona, ma con un array di record?

Se vuoi creare un array di stringhe costanti puoi farlo anche così:

Codice: [Seleziona]
var
 strarr: array of string = ['uno', 'due', 'tre'];

Per un array l'indicazione che pensavo di fornirti è creare una procedura di inizializzazione, ovviamente da chiamare per ciascun elemento. Non ho conoscenza di una procedura che consente di inizializzare a dei valori voluti un array di record.
Perchè farlo a differenza di quanto suggerito da @Narciso (fermo restando che và comunque bene anche la sua soluzione): perchè nel caso tu cambi la struttura puoi sfruttare la procedura per fare si che la compilazione non avvenga se non aggiorni l'inizializzazione. Io sui record uso molto spesso le procedure per inserire i dati, non inserisco i dati direttamente nei campi del record perchè se cambio qualcosa (refactoring) con le procedure ho una segnalazione di errore e ciò mi consente di modificare il codice a "colpo sicuro".

Esempio:

Codice: [Seleziona]
type
  RProva = record
    private
      fNome: string;
      fCognome: string;
    public
      procedure Init(const Nome: string; const Cognome: string);
  end;

....
....

procedure RProva.Init(const Nome, Cognome: string);
begin
  fNome := Nome;
  fCognome := Cognome;
end;

...
...

var
  Prova: array of RProva;
  //EDIT2: al posto della definizione di Prova in modalità classica, puoi usare anche i generici se ti piace di più, non cambia il codice:
  //Prova: TArray<RProva>;
  i: RProva;
begin
  SetLength(Prova, 10);
  for i in Prova do
     i.Init('Non usato', 'Non usato');
end;

Se aggiorno il record con ad esempio l'aggiunta di una data:
Codice: [Seleziona]
type
  RProva = record
    private
      fNome: string;
      fCognome: string;
      fDataNascita: TDate;
    public
      procedure Init(const Nome: string; const Cognome: string; DataNascita: TDate);
  end;

La compilazione mi genererebbe un errore ovunque usi la procedura Init, e così via ove usi le funzioni o procedure per inserire i dati (o anche per leggerli se fosse importante).
EDIT: per spiegare meglio, se uso direttamente i campi potrei dimenticare da qualche parte nel sorgente di settare la data di nascita senza che me ne accorga, e ciò non è bello ...

E' leggermente differente che usare i campi direttamente, ma questo è un mio modo di programmare, non deve essere preso assolutamente come campione.

Ciao
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 09, 2025, 04:08:58 pm
Ti ringrazio della risposta, ma non è quello che cercavo. Cercherò e se trovo Vi saprò dire.
Capisco i tuoi esempi, es è come ho fatto fin'ora, ma volevo fare come nell'esempio scritto sopra , ripeto con TStringArray funziona e non so come fare (o non mi ricordo) con gli array di record.

Grazie a tutti.
Titolo: Re:Inizializzazione array di record
Inserito da: nomorelogic - Marzo 10, 2025, 10:27:28 am
forse vuoi usare la .Create con la sintassi che si usa per le costanti tipizzate?

https://forum.lazarus.freepascal.org/index.php/topic,61986.msg468094.html#msg468094 (https://forum.lazarus.freepascal.org/index.php/topic,61986.msg468094.html#msg468094)
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 10, 2025, 11:39:31 am
Forse non mi sono spiegato bene. Io un array di stringhe posso inizializzarlo così:
Codice: [Seleziona]
program Project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Sysutils,
  Classes
  { you can add units after this };

var
  c : TStringArray;
begin
  c := TStringArray.Create('eee', 'rrr');
end.
                   

Però non riesco a farlo con un array di record

P.S. @nomorelogic  esempio interessante
Titolo: Re:Inizializzazione array di record
Inserito da: nomorelogic - Marzo 10, 2025, 03:36:30 pm
se guardi nel link che ti ho indicato c'è questo pezzo di codice

Codice: [Seleziona]
type
  tConstArray  = array of TVarRec;
 
[...]

var
  x: TConstArray;
  y: TConstArray =
  (
    (vtype : vtChar;    vchar : '1'),
    (vtype : vtInteger; vinteger : 1),
    (vtype : vtPointer; vpointer : nil)
  );
 


non so se funziona (oggi non riesco a provare in quanto sono in giro)
ma pensavo tu intendessi qualcosa del genere

Codice: [Seleziona]

x:= TConstArray.Create (
 
         (
            (vtype : vtChar;    vchar : '1'),
            (vtype : vtInteger; vinteger : 1),
            (vtype : vtPointer; vpointer : nil)
          )

);


Titolo: Re:Inizializzazione array di record
Inserito da: DragoRosso - Marzo 10, 2025, 03:49:54 pm
Quel "modo" di creare gli array, se si legge bene l'articolo, ha tutta una serie di controindicazioni. Prima di usarlo io ci penserei N (con N che tende all'infinito e oltre) volte ....

E' una mimica usata per il compilatore (ci sono diverse discussioni anche su Delphi) per consentire un uso simile al WriteLn(var1, var2, var3, var n) ...

Quando viene usato, non c'è modo di sapere da parte di chi riceve questo "array" (se si può chiamare tale) quanti elementi ci sono, è necessario conoscerli a priori (o ci devo abbinare qualche altro dato che mi informi su ciò).

Però, ammettendo che si voglia usare, non penso sia ancora quello che vuole @Cappe, magari mi sbaglio però ...

Titolo: Re:Inizializzazione array di record
Inserito da: nomorelogic - Marzo 10, 2025, 04:35:50 pm
infatti non so se ho capito il problema
comunque, con l'occasione, questo è il link della documentazione ufficiale

(cercate la sezione "Dynamic array constructor")

https://www.freepascal.org/docs-html/ref/refsu14.html#x38-520003.3.1 (https://www.freepascal.org/docs-html/ref/refsu14.html#x38-520003.3.1)
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 11, 2025, 06:18:04 am
L'idea è questa
Codice: [Seleziona]
program Project1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes
  { you can add units after this };

type
  calimero = record
    sonoNero : Boolean;
  end;
  sfigati = array of calimero;

var
  io : calimero;
  tu : calimero;
  noi : sfigati;
begin
  io.sonoNero:=True;
  tu.sonoNero:=True;
  noi := sfigati.Create(io, tu);
end.       
e funziona.

Vorrei fare  noi := sfigati.Create(io, tu); senza dichiarare le variabili io e tu, cioè se è possibile assegnare i valori del record direttamente dentro  noi := sfigati.Create
Titolo: Re:Inizializzazione array di record
Inserito da: DragoRosso - Marzo 11, 2025, 09:09:40 am
@cappe

... ma quanto sono indietro? ... non mi sono mai chiesto nulla sulla esistenza di un "helper" sul create di un array. Sempre che sia un helper e non un metodo risolto dal compilatore.

Dopo una breve ricerca non ho trovato nulla sul "create" di un array in quel modo che hai indicato (e su Delphi funziona) .....

Questa illuminazione mattutina mi mette curiosità sul sapere se esiste un qualcosa per fare quello che suggerisci.
Titolo: Re:Inizializzazione array di record
Inserito da: nomorelogic - Marzo 11, 2025, 09:11:36 am
dovresti provare con qualcosa tipo

Codice: [Seleziona]

noi := sfigati.Create(  ( sononero: True ), ( sononero: True ) );



oppure se puoi fare in modo che calimero sia un oggetto

Codice: [Seleziona]

noi := sfigati.Create(  TCalimero.Create(true), TCalimero.Create(true) );


è da provare ma la strada credo sia questa
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 11, 2025, 09:19:17 am
già provato non funziona. Un'idea sarebbe utilizzare variabili inline ma ci sono su delphi. Forse sulle prossime versioni di fpc o in qualche modo che non conosco.

dovresti provare con qualcosa tipo

Codice: [Seleziona]

noi := sfigati.Create(  ( sononero: True ), ( sononero: True ) );



oppure se puoi fare in modo che calimero sia un oggetto

Codice: [Seleziona]

noi := sfigati.Create(  TCalimero.Create(true), TCalimero.Create(true) );


è da provare ma la strada credo sia questa
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 11, 2025, 09:30:12 am
Sta buono, che più bravo di me.
Il punto è che a volte in questo modo, a mio avviso, si scrive codice più pulito.

@cappe

... ma quanto sono indietro? ... non mi sono mai chiesto nulla sulla esistenza di un "helper" sul create di un array. Sempre che sia un helper e non un metodo risolto dal compilatore.

Dopo una breve ricerca non ho trovato nulla sul "create" di un array in quel modo che hai indicato (e su Delphi funziona) .....

Questa illuminazione mattutina mi mette curiosità sul sapere se esiste un qualcosa per fare quello che suggerisci.
Titolo: Re:Inizializzazione array di record
Inserito da: DragoRosso - Marzo 11, 2025, 12:27:18 pm
Ho visto in Delphi come vengono creati gli array dinamici (Create(...) come indicato), ed in effetti è un costrutto del compilatore (mappato su dei metodi della System) che usa poi le RTTI per gestire i parametri.

Può essere che effettivamente si possano definire direttamente i "campi" nel Create.

A parte la curiosità, però nutro dei dubbi sulla validità effettiva di scrivere eventualmente in quel modo con delle "costanti" il tutto. Diciamo che non è proprio elegante e chiaro ... almeno così pare a me rivedendo il tutto.

E poi rimane comunque il fatto dell'eventuale refactoring, e con un codice scritto così la vedo comunque dura effettuarlo a colpo sicuro.
Titolo: Re:Inizializzazione array di record
Inserito da: nomorelogic - Marzo 11, 2025, 08:03:56 pm
ok, ok
quà c'è un workaround, lo ammetto (la funzione _GetSfigato)

però così il sorgente è comunque abbastanza leggibile e manutenibile
inoltre ho scoperto (si perché non lo sapevo o l'avevo dimenticato  :o) che si può creare un array anche con le parentesi quadre...

Codice: [Seleziona]
program test_creazione_array;
type
  Tcalimero = record
    sonoNero : Boolean;
  end;
  Tsfigati = array of Tcalimero;

  function _GetSfigato(AValue: boolean): Tcalimero;
  begin
    result.sonoNero:=AValue;
  end;

var
  ErrorMsg: String;
  sf1, sf2, sf3, sf4: Tsfigati;
  a1, a2: Tcalimero;

begin

  a1.sonoNero:=True;
  a2.sonoNero:=True;

  sf1 := Tsfigati.create(a1,a2);
  WriteLn('sf1: ', Length(sf1));

  sf2 := [a1,a2];
  WriteLn('sf2: ', Length(sf2));

  sf3 := [ _GetSfigato(True), _GetSfigato(True) ];
  WriteLn('sf3: ', Length(sf3));

  sf4 := Tsfigati.Create( _GetSfigato(True), _GetSfigato(True) );
  WriteLn('sf4: ', Length(sf4));

end.
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 11, 2025, 08:31:22 pm
Bravo, buona soluzione.
Titolo: Re:Inizializzazione array di record
Inserito da: DragoRosso - Marzo 11, 2025, 09:40:55 pm
inoltre ho scoperto (si perché non lo sapevo o l'avevo dimenticato  :o) che si può creare un array anche con le parentesi quadre...

... te l'avevo indicato in un post precedente (come var, ma ovviamente funziona anche come assegnazione pura) ....  ;)

Comunque complimenti per la fantasia ... anche se continuo ad avere perplessità (ma rimangono assolutamente mie).
Titolo: Re:Inizializzazione array di record
Inserito da: nomorelogic - Marzo 12, 2025, 09:23:27 am
mi rendo conto che la senilità avanza inesorabile  ;D
Titolo: Re:Inizializzazione array di record
Inserito da: cappe - Marzo 12, 2025, 04:19:56 pm
Io volevo cercavo la soluzione nel linguaggio, dovrebbe esserci, ma ho perso troppo tempo.