Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: petrusic - Marzo 13, 2021, 10:58:39 pm

Titolo: Questa è bella
Inserito da: petrusic - Marzo 13, 2021, 10:58:39 pm
Riporto un immagine relativa ad uno spezzone di codice dove esistono in cascata più if. Ebbene il compilatore segnala un errore ad una prima Else, mentre, più avanti , per lo stesso tipo di sequenza, non segnala niente.
Mi sembrava una banalità, ma, sostituendo Else , posta immediatamente dopo, con un'altra if (<>), vengono segnalati altri errori più sotto.
Non descrivo tutto dettagliatamente per ingarbugliare anche l'esposizione del mio problema.
l'errore segnalato è:
Citazione
frm2.pas(413,5) Fatal: Syntax error, ";" expected but "ELSE" found
Devo dire che nella parte dichiarativa della procedure ho inserito tipe e var di puntamento ai miei 3 array globali:
Codice: [Seleziona]
procedure TForm2.CompilaFrm2(sdtTratt, rifTb:String);
//procedure TForm2.compilaFrm2(sdtTratt: Integer; rifTb:String);   // carica in GridMovv i movimenti presenti in tbMovv(M) o in tbResta(R)
type
  PtbCor = ^string;     // crea un puntatore generico di tipo String
  PtbMov = ^TtbMovv;
  PtbRes = ^TtbResta;
  PtbRiep = ^TtbRiep;

var
  tbCorr: PtbCor;
  tbMovim: PtbMov;
  tbResCas: PtbRes;
  tbQuadra: PtbRiep;

  swPrimo: Boolean;
  sw: Boolean = False;

  i, i1, nuRgTbCorr, nuRgTbMovv, nuRgTbRiep, nuRgTbResta: Integer;
  nuRgdtTratt: Integer = 0;

begin                                           
Che sia qui il problema?

Titolo: Re:Questa è bella
Inserito da: nomorelogic - Marzo 13, 2021, 11:26:34 pm
quando una if ha anche la clausola else, non ci deve essere il ; dopo l'end che precede l'else

è errato scrivere

Codice: [Seleziona]
if condizione 
  begin
     istruzione1;
  end;
  else
    begin
      istruzione2;
   end;

in quanto il ; chiude l'istruzione

è invece corretto:
Codice: [Seleziona]
if condizione 
  begin
     istruzione1;
  end
  else
    begin
      istruzione2;
   end;
Titolo: Re:Questa è bella
Inserito da: petrusic - Marzo 14, 2021, 04:15:01 pm
Sicuramente ho commesso uno strafalcione.
Tuttavia, prima di scrivere, ho provato anche la soluzione "if ... end else" (senza quindi il ;) ed  il compilatore mi segnalato altri errori che per me sono indecifrabili.
Allego l'immagine con la segnalazione d'errore nel codice, mentre riporto qui sotto il messaggio d'errore :
Citazione
frm2.pas(415,22) Error: Element zero of an ansi/wide- or longstring cannot be accessed, use (set)length instead
frm2.pas(427,22) Error: Element zero of an ansi/wide- or longstring cannot be accessed, use (set)length instead
L'errore è sicuramente legato al cattivo uso che faccio, dentro la unit frm2, nel puntare all'indirizzo di memori dei miei array globali, dchiarati nella unit frmmain:
Codice: [Seleziona]
unit frmmain;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, DB, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
  ExtCtrls, fpspreadsheet, laz_fpspreadsheet, Process, ZConnection, ZDataset,
  fpstypes; // , flcDynArrays; dovrebbe permettere di riordinare la seuenza degli elementi di un vettore

type

  { TForm1 }
  TtbMovv = array of array of String;
  TtbResta = array of array of String;
  TtbRiep = array of array of String;

  TForm1 = class(TForm)                                 
. . .

Non ho saputo trovare nessuna nota informativa sull'uso di variabili di puntamento agli array. Perciò, quello che ho trovato e letto, l'ho interpretato così:
Codice: [Seleziona]
unit frm2;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, DB, Forms, Controls, Graphics, Dialogs, StdCtrls, Grids, utilmie,
  ExtCtrls, XMLPropStorage;

type

  { TForm2 }

  TForm2 = class(TForm)         
. . .
procedure TForm2.CompilaFrm2(sdtTratt, rifTb:String);
//procedure TForm2.compilaFrm2(sdtTratt: Integer; rifTb:String);   // carica in GridMovv i movimenti presenti in tbMovv(M) o in tbResta(R)
type
  PtbCor = ^string;     // crea un puntatore generico di tipo String
  PtbMov = ^TtbMovv;
  PtbRes = ^TtbResta;
  PtbRiep = ^TtbRiep;

var
  tbCorr: PtbCor;
  tbMovim: PtbMov;
  tbResCas: PtbRes;
  tbQuadra: PtbRiep;

  swPrimo: Boolean;
  sw: Boolean = False;

  i, i1, nuRgTbCorr, nuRgTbMovv, nuRgTbRiep, nuRgTbResta: Integer;
  nuRgdtTratt: Integer = 0;

begin
  case rifTb of
    'M':
      begin
        nuRgTbCorr:= Length(tbMovv) div 5;
        tbCorr:= @tbMovim;    // carico in tbCorr l'indirizzo di memoria tbMovim
      end;
    'R':
      begin
        nuRgTbCorr:= Length(tbResta) div 4;
        tbCorr:= @tbResCas;       // carico in tbCorr l'indirizzo di memoria di TtbResta
      end;
    'Q':
      begin
        nuRgTbCorr:= Length(tbRiep) div 6;
        tbCorr:= @tbQuadra;       // carico in tbCorr l'indirizzo di memoria di TtbRiep
      end;
  end;                                                 
Titolo: Re:Questa è bella
Inserito da: DragoRosso - Marzo 14, 2021, 04:56:48 pm
Perchè usi i puntatori: a meno che non devi interfacciarti con librerie fatte tipicamente in C o C++ non c'è necessità di usare i puntatori.

Dichiarazione di una stringa:

var
   pippo: string;

Accesso al primo carattere della stringa:

  if pippo[1] = 'X' then
    begin
        //Fai qualcosa
    end;

Attento che:

Ansistring e WideString hanno la composizione dei caratteri diversa, ossia ansistring è formata da una serie di caratteri di 8 bit, mentre widestring (così come unicode) invece ha una lunghezza del carattere di 16 bit.

Se usi le funzioni tipiche delle stringhe non noti la differenza, mentre se usi puntatori o movimenti di memoria puoi andare incontro a spiacevoli inconvenienti.

Inoltre la comparazione qui sopra indicata è "CASE SENSITIVE", cioè 'X' e 'x' sono diversi.

P.S.: OVVIAMENTE NON PUOI ACCEDERE AD UNA POSIZIONE che và oltre la lunghezza della stringa stessa.

pippo := 'Ciao';
if pippo[7] = ....
  VIENE GENERATA UNA ECCEZIONE A RUNTIME !!!

Titolo: Re:Questa è bella
Inserito da: DragoRosso - Marzo 14, 2021, 05:28:20 pm
Citazione
Non ho saputo trovare nessuna nota informativa sull'uso di variabili di puntamento agli array. Perciò, quello che ho trovato e letto, l'ho interpretato così:

var
   tantipippo: array of array of string;    //array bidimensionale

//prima di tutto devi creare l'istanza dell'array con un numero di elementi (anzi con due numeri di elementi)
//qui te la faccio lunga, per dimostrarti il concetto
  setlegnth(tantipippo, 5);
  setlength(tantipippo[0], 3);
  setlength(tantipippo[1], 4);
  setlength(tantipippo[2], 3);
  setlength(tantipippo[3], 7);
  setlength(tantipippo[4], 3);
//avrai un array non simmetrico con un numero variabile di "sottoelementi", accederai così:

  tantipippo[0][0] := 'Sono il primo elemento in assoluto';
  tantipippo[0][1] := 'Sono il secondo elemento della prima riga';
  tantipippo[0][2] := 'Sono l'ultimo elemento della prima riga';

  tantipippo[1][0] := 'Sono il primo elemento della seconda riga';
  tantipippo[1][1] := 'Sono il secondo elemento della seconda riga';
  tantipippo[1][2] := 'Sono il terzo elemento della seconda riga';
  tantipippo[1][3] := 'Sono l'ultimo elemento della seconda riga';

  e così via .....

  tantipippo[0][0][1] := 'A';

  ShowMessage(tantipippo[0][0]);

  risualtato =>   Aono il primo elemento in assoluto


Titolo: Re:Questa è bella
Inserito da: petrusic - Marzo 14, 2021, 06:47:14 pm
Perchè usi i puntatori: a meno che non devi interfacciarti con librerie fatte tipicamente in C o C++ non c'è necessità di usare i puntatori.
Nello spezzone di codice che ho riportato nel mio precedente post, a seconda del contenuto del paramtetro "rifTb"('M', 'R', 'Q'), devo accedere ai contenuto di un o dei tre array globali corrispondenti.
a me sembra che sia più logico farlo attraverso i puntatori.

L'alternativa a tale metodo è quella di copiare tutto l'array occorrente  in locale e poi utilizzare detto contenuto.
In questa fase di esercitazione-studio vorrei approfondire il concetto del puntamento agli array, però se è veramente così arduo addentrarsi in simili argomentazioni, allora sarò costretto, mio malgrado a rinunziare.

Con ciò voglio dire che conosco la strada alternativa, ma, abbandonando il percorso iniziato sui puntamenti agli array, non cresco nelle mie pur modeste conoscenze del pascal.
Titolo: Re:Questa è bella
Inserito da: DragoRosso - Marzo 14, 2021, 07:45:06 pm
 ... scusami, non avevo intenzione di scoraggiarti dal tuo intento (che non avevo compreso) ...

Vorrei darti due consigli:

1) Attenzioni ai tipi: ad esempio definisci "TtbMovv" come un array bidimensionale, e poi, assegni a "tbCorr" (che è un puntattore a una stringa) il puntatore all'array bidimensionale. Questo non và bene, almeno da quello che adesso ho capito. In questo modo tbcorr punterà al primo elemento dell'array bidimensionale, ma non è garantito che così tu possa accedere all'array bidimensionale completo.
Cerca di mantenere la corrispondenza tra tipi. Non saprei in Lazarus (sono nuovo di questo ambiente) come fare in maniera più formale, ma eventualmente forse ti conviene usare un puntatore generico e fare poi il casting.

2) Ricordati che un array (normalmente) ha il primo elemento in posizione 0 (chiamalo indice o altro), ma le stringhe (che sono anch'esse un array) hanno il primo elemento in posizione 1 (indice).

Lascio ad altri più esperti di Lazarus ad indicarti eventualmente la strada.

Buon proseguimento.
Titolo: Re:Questa è bella
Inserito da: petrusic - Marzo 15, 2021, 09:04:35 am
1) Attenzioni ai tipi: ad esempio definisci "TtbMovv" come un array bidimensionale, e poi, assegni a "tbCorr" (che è un puntattore a una stringa) il puntatore all'array bidimensionale. Questo non và bene, almeno da quello che adesso ho capito. In questo modo tbcorr punterà al primo elemento dell'array bidimensionale, ma non è garantito che così tu possa accedere all'array bidimensionale completo.
Cerca di mantenere la corrispondenza tra tipi.
Purtroppo l'impiego dei puntatori rappresenta per me un ostacolo non facile da superare, anche per la mancanza di guide adeguate in merito all'argomento, soprattutto per i puntatori agli array.
Quando, inizialmente, ho dichiarato il puntatore agli array globali del mio programma, ho utilizzato una dichiarazione del tipo
Codice: [Seleziona]
  PtbCor = ^array of array of string;
ma il compilatore si arrabbia e mi dice
Citazione
frm2.pas(395,13) Error: Type identifier expected
frm2.pas(395,13) Fatal: Syntax error, ";" expected but "ARRAY" found

Ecco perchè poi ho usato la dichiarazione: |PtbCor = ^string;|
Effettivamente, dal punto di vista logico, mi sembra una nota stonata, ma non so se, per una peculiarità del linguaggio, non possa scrivere diversamente.


Titolo: Re:Questa è bella
Inserito da: DragoRosso - Marzo 15, 2021, 03:39:56 pm
Prova questo e vedi se come spunto può starci (ho copiato solo il contenuto della Unit, la Form ha un pulsante Button1)

Codice: [Seleziona]
unit Unit1;

{$mode objfpc}{$H+}

interface

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

type
  tar = array of array of string;
  ptar = ^tar;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;
  Arr1: tar;
  pArr2: ptar;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  //Riempimento demo dell'array e sua istanziazione
  setlength(Arr1, 3);
  setlength(Arr1[0],2);
  setlength(Arr1[1],3);
  setlength(Arr1[2],2);
  Arr1[0][0] := '00';
  Arr1[0][1] := '01';
  Arr1[1][0] := '10';
  Arr1[1][1] := '11';
  Arr1[1][2] := '12';
  Arr1[2][0] := '20';
  Arr1[2][1] := '21';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  //Assegna ad Arr2 il puntatore a Arr1: gli array in questo modo sono di fatto "clonati" e condividono la stessa area di memoria
  pArr2 := @Arr1;
  ShowMessage(pArr2^[1][2]);
  Arr1[1][2] := '45';
  ShowMessage(pArr2^[1][2]);
end;

procedure TForm1.FormDestroy(Sender: TObject);
var j, k: cardinal;
begin
  //Procedura per la deallocazione di memoria: tutto ciò che viene creato a "mano" deve essere deallocato a "mano"
  for j := Low(Arr1) to High(Arr1) do
    for k := Low(Arr1[j]) to High(Arr1[j]) do
      setlength(Arr1[j][k], 0);
  setlength(Arr1, 0);
end;

end.
Titolo: Re:Questa è bella
Inserito da: nomorelogic - Marzo 16, 2021, 06:41:19 pm
DragoRosso, per favore, quando includi del sorgente, usa i tag "code"
si tratta del bottone col simbolo del cancelletto (o hashtag) "#"
Titolo: Re:Questa è bella
Inserito da: DragoRosso - Marzo 16, 2021, 09:31:31 pm
 :) Fatto.
Titolo: Re:Questa è bella
Inserito da: nomorelogic - Marzo 17, 2021, 08:10:52 am
Non ho saputo trovare nessuna nota informativa sull'uso di variabili di puntamento agli array. Perciò, quello che ho trovato e letto, l'ho interpretato così:

ciao

fondamentalmente un array lo devi vedere come un puntatore ad un'area consecutiva di memoria dedicata alla memorizzazione indicizzata di variabili dello stesso tipo


dai un'occhiata a questi link

https://freepascal.org/docs-html/ref/refsu14.html
https://wiki.lazarus.freepascal.org/Multidimensional_arrays

e poi anche qua
https://www.tutorialspoint.com/pascal/pascal_arrays.htm