DOMANDA Free Pascal - come ottenere il numero totale degli elementi di una matrice

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
Nel mio percorso d'apprendimento, ho provato a dichiarare matrici per riferimento e richiamarne poi il contenuto all'interno di una procedure. Ciò mi si è reso necessario perchè le mie matrici non hanno tutte la stessa dimensione e la procedura a cui è affidato il trattamento, ne riceve soltanto una, quindi non ne conosce la dimensione.

La mia difficoltà è che non riesco a superare la compilazione per un errore nella riga di calcolo del numero di elementi della matrice in ingresso della procedura incaricata del suo trattamento.

Dopo questa premessa allego i passi di programma interessanti per lo scopo, fino alla riga che produce erroe in compilazione:

Codice:
unit cofamtrasf;   {Classe: tipo Form_Main}

--- bla --- bla ---

private

    type

      PtbCoCas = ^TtbCoCas;

      TtbCoCas = array[0..1, 0..1] of LongInt;

      PtbCoPartMov = ^TtbCoPartMov;

      TtbCoPartMov = array[0..2, 0..1] of LongInt;

      PtbCoPreMom = ^ TtbCoPreMom;

      TtbCoPreMom = array[0..1, 0..1] of LongInt;

  const

    TtbCas: TtbCoCas = ((101001000, 101001997),

                      (101001990, 101001999));

    TtbPartMov: TtbCoPartMov = ((102001000, 103999999),

                              (105001000, 203999999),

                              (205001000, 999999999));

    TtbPreMom: TtbCoPreMom = ((104001000, 104999000),

                          (204001000, 204999000));

--- bla --- bla ---
procedure carCombo(Var TtbCoVoci:LongInt);
var
  i, ii, iMax: integer;
begin
    iMax= ... (vedi sotto alcune delle prove fatte)

--- bla --- bla ---
procedure TForm1.VoMasPartChange(Sender: TObject);

begin
     case VoMasPart.Text of
          'Cassa':
             carCombo(TtbCas);
          'Partmovv':
            carCombo(TtbPartMov);
          'Prestmom':
            carCombo(TtbPreMom);
     end;
end;
Per provare l'istruzione iMax=, onde ottenere l'estrazione del n. elementi della matrice corrente, ho fatto diverse ricerche, fino all'esasperazione, ma, dalle ricerche fatte non sono riuscito a capire quale criterio corretto avrei potuto applicare, perchè non ne ho trovati.
Riporto alcune delle istruzioni che ho provato
Codice:
iMax= (TtbCoVoci.Length);     -> produce l'errore "illegal qualifier" (Length)
iMax= Length(TtbCoVoci);     -> produce l'errore "Type Mismatch" (Length)
iMax= size(TtbCoVoci);     -> produce l'errore "identifier size not found
iMax= (TtbCoVoci.size);     -> produce l'errore "illegal expression"
Ebbene, come al solito in questi casi, l'errore è una solenne banalità, ma io non sono riuscito a venirne fuori.
 
Ultima modifica:

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
L'assegnazione a variabile in Pascal si fa con l'operatore :=, non con il solo uguale.
Esempio: iMax := Length(TtbCas);
 

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
Fatto, ma è cambiato solo il codice di errore.
 

Allegati

  • Screenshot_2020-04-05_21-37-38.png
    Screenshot_2020-04-05_21-37-38.png
    72.4 KB · Visualizzazioni: 83

BAT

Moderatore
Staff Forum
Utente Èlite
22,668
11,452
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Leggi il messaggio di errore:
dopo l'inizializzazione del for si aspettava di trovare TO invece ha incontrato un punto e virgola, infatti hai messo un ";" dopo l'assegnazione alla "i" indice del for. Togli il ";"
 

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
fatto, ma l'errore type mismatch è rimasto tale e quale
 

Allegati

  • Screenshot_2020-04-05_22-33-44.png
    Screenshot_2020-04-05_22-33-44.png
    83.8 KB · Visualizzazioni: 81

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
Il tipo SizeInt è un alias per LongInt.
Credo che il problema sia un altro: il parametro di input della procedura carCombo, TtbCoVoci, che dovrebbe essere un array bidimensionale di interi, è dichiarato come una variabile semplice di tipo intero. L'errore type mismatch si riferisce a questo.
Ora, il problema è che, da quello che ho capito, FreePascal non consente di dichiarare come parametro un open array bidimensionale, dove per open array si intende un array di cui non è specificata la dimensione. Per cui ci sono varie strade:
1) Definire un tipo appropriato per un array bidimensionale e dichiarare il parametro di quel tipo. Lo svantaggio è che le dimensioni della matrice saranno fisse (nell'esempio, 2x2).
Codice:
type
    T2DMatrix = array[0..1, 0..1] of LongInt;

var
    a: T2DMatrix = ((1, 2), (3, 4));

procedure carCombo(Var TtbCoVoci: T2DMatrix);
Var
    i, j: integer;
begin
    for i := 0 to High(TtbCoVoci) do
      for j := 0 to High(TtbCoVoci[i]) do
        writeln(TtbCoVoci[i, j]);
end;

begin
    carCombo(a);
    readln();
end.
2) Come sopra, ma usando il nuovo tipo solo per l'array esterno della matrice. In questo modo la matrice avrà un numero fisso di righe (due nell'esempio qui sotto, come nelle matrici del tuo codice), ma potrà avere un numero variabile di colonne.
Codice:
type
    Row = array[0..1] of LongInt;

var
    a: array[0..1] of Row = ((1, 2), (3, 4));

procedure carCombo(Var TtbCoVoci: array of Row);
Var
    i, j: integer;
begin
    for i := 0 to High(TtbCoVoci) do
      for j := 0 to High(TtbCoVoci[i]) do
        writeln(TtbCoVoci[i, j]);
end;

begin
    carCombo(a);
    readln();
end.
3) Dichiarare la matrice come array bidimensionale dinamico. Più precisamente, array dinamico di array dinamici. In questo modo l'array potrà avere qualunque dimensione, sia in righe che in colonne. Lo svantaggio è prestazionale, perché un array di questo tipo è implementato come un array di puntatori ad array, quindi le varie righe sono memorizzate in aree non contigue di memoria, il che potrebbe rendere più lenti eventuali calcoli matriciali.
Codice:
type
    T2DMatrix = array of array of LongInt;
    Row = array of LongInt;
var
    a: T2DMatrix;


procedure carCombo(Var TtbCoVoci: T2DMatrix);
Var
    i, j: integer;
begin
    for i := 0 to High(TtbCoVoci) do
      for j := 0 to High(TtbCoVoci[i]) do
        writeln(TtbCoVoci[i, j]);
end;

begin
    a := T2DMatrix.create(Row.create(1, 2),
                          Row.create(3, 4));
    carCombo(a);
    readln();
end.
4) Simulare la matrice con un array monodimensionale. In questo modo puoi dichiarare il parametro di input della procedura come un open array, senza specificarne le dimensioni, che puoi passare a loro volta come parametro. Per avere una matrice NxM, dichiari un array di NxM elementi. Per iterare su di esso come se fosse una matrice, basta usare la seguente formula: matrice[ i , j ] = array[ i*m + j ]. Qui maggiori info.
Codice:
var
    a: array[0..3] of LongInt = (1, 2, 3, 4); 
    {a: array[0..1, 0..1] of LongInt((1,2),
                                     (3,4))}

procedure carCombo(Var TtbCoVoci: array of LongInt; rows, col: integer);
Var
    i, j: integer;
begin
    for i := 0 to rows - 1 do
      for j := 0 to col - 1 do
        writeln(TtbCoVoci[i*col + j]); { corrisponde a TtbCoVoci[i, j]}
end;

begin
    carCombo(a, 2, 2);
    readln();
end.
 
Ultima modifica:
  • Mi piace
Reazioni: Mursey

BAT

Moderatore
Staff Forum
Utente Èlite
22,668
11,452
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Permittimi un altro paio di suggerimenti:
affinché il codice sia mantenibile, e per facilitare la correzione degli errori ed ottenere aiuto da terzi, il codice deve essere leggibile...
cerca di dare ai nomi di procedure e funzioni dei nomi significativi invece che criptici (attualmente hanno senso solo per te) e ABBONDA in commenti che non fanno mai male;
per quanto riguarda gli array, il Pascal è efficientissimo con quelli a dimensione fissa: se le dimensioni massime che prevedi di usare sono ragionevolmente limitate (in baso al tipo di dato che immagazzina), non ti conviene complicarti la vita. Fissa una volta per tutte le dimensioni ed alloca tutto quanrto, con tutti i gigabyte di RAM che abbiamo a disposizioni, un array da qualche decina di mega non ti manda in crash l'applicazione.
 
  • Mi piace
Reazioni: fabio93

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
Grazie a tutti per l'aiuto ed i suggerimenti.

..., il problema è che, da quello che ho capito, FreePascal non consente di dichiarare come parametro un open array bidimensionale, dove per open array si intende un array di cui non è specificata la dimensione. Per cui ci sono varie strade
Ho guardato co attenzione l'ampia casistica di scelte che ha gentilmente preparato per aiutarmi a risolvere la condizione di errore che da qualche giorno mi tiene bloccato.
Fra le tante credo che quella più percorribile per me, in base alle mie modeste conoscenze ad oggi, sia la n.4:
4) Simulare la matrice con un array monodimensionale. In questo modo puoi dichiarare il parametro di input della procedura come un open array, senza specificarne le dimensioni, che puoi passare a loro volta come parametro. Per avere una matrice NxM, dichiari un array di NxM elementi. Per iterare su di esso come se fosse una matrice, basta usare la seguente formula: matrice[ i , j ] = array[ i*m + j ].
Ho cominciato la modifica del programma, ma mi sono fermato prima di mettere le mani alla procedure che dovrebbe scorrere il sottoinsieme dell'array.
Ciò perchè, lanciando la compilazione, si è manifestato il solito errore incomprensibile, almeno per me, già nelle righe di dichiarazione dell'array monodimensionale:

Codice:
unit cofamtrasf;   {Classe: tipo Form_Main}

{$mode objfpc}{$H+}

interface

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, db, Forms, Controls, Graphics, Dialogs, StdCtrls, EditBtn,
  ExtCtrls, DBGrids, DBCtrls, ZConnection, ZDataset;

type
  { TForm1 }

  TForm1 = class(TForm)
    VoMasArri: TComboBox;
    VoMasPart: TComboBox;
    contabfamDB: TDataSource;
    DBSotCtoArri: TDBComboBox;
    DBVoSecArri: TDBComboBox;
    DbVoSecPart: TDBComboBox;
    DBSotCtoPart: TDBComboBox;
    pExit: TButton;
    PNoVis: TButton;
    DtFin: TDateEdit;
    DtIni: TDateEdit;
    Label5: TLabel;
    Label6: TLabel;
    pVia: TButton;
    CoVoPart: TEdit;
    CoVoArri: TEdit;
    Label3: TLabel;
    Label4: TLabel;
    MovDest: TGroupBox;
    SotCtoPart: TComboBox;
    Label2: TLabel;
    SotCtoArri: TComboBox;
    VoSecPart: TComboBox;
    Label1: TLabel;
    MovTrasf: TGroupBox;
    VoSecArri: TComboBox;
    ZConnection1: TZConnection;
    ZQuery1: TZQuery;
    procedure FormActivate(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure pExitClick(Sender: TObject);
    procedure pExitEnter(Sender: TObject);
    procedure pExitExit(Sender: TObject);
    procedure PNoVisEnter(Sender: TObject);
    procedure VoMasPartChange(Sender: TObject);

  private

  var
  TtbConti: array[0..13] of LongInt= (101001000, 101001997,      // 1° range conti di Cassa (tabella movimgg)
                          101001990, 101001999,     // ultimo range conti di Cassa (tabella movimgg)
                          102001000, 103999999,     // 1° range conti di contropartita (tabella partmovv)
                          105001000, 203999999,     // 2° range conti di contropartita (tabella partmovv)
                          205001000, 999999999,     // ultimo range conti di contropartita (tabella partmovv)
                          104001000, 104999000,     // 1° range conti di contropartita (tabella prestmom)
                          204001000, 204999000);     // ultimo range conti di contropartita (tabella prestmom)
  public

    end;
come si può constatare dall'allegato.
 

Allegati

  • Screenshot_2020-04-06_23-06-40.png
    Screenshot_2020-04-06_23-06-40.png
    68.5 KB · Visualizzazioni: 82

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
No Mursey, scusami se non condivido. Infatti predentemente l'errore si manifestava durante l'esecuzione della procedura carCombo, mentre ora si manifesta sempre un errore, ma con un altro codice, e nel gruppo di righe relative alla dichiarazione dell'array:
Codice:
  var
  TtbConti: array[0..13] of LongInt = (101001000, 101001997,      // 1° range conti di Cassa (tabella movimgg)
                          101001990, 101001999,     // ultimo range conti di Cassa (tabella movimgg)
                          102001000, 103999999,     // 1° range conti di contropartita (tabella partmovv)
                          105001000, 203999999,     // 2° range conti di contropartita (tabella partmovv)
                          205001000, 999999999,     // ultimo range conti di contropartita (tabella partmovv)
                          104001000, 104999000,     // 1° range conti di contropartita (tabella prestmoom)
                          204001000, 204999000);     // ultimo range conti di contropartita (tabella prestmoom)
ed esattamente alla prima di esse, cosa che prima dell'ultima modifica non si presentava.
Potrei provare a caricare i valori dell'array più avanti, ma, così facendo, finirei di imparare.
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
L'assegnazione si fa con :=, ma l'inizializzazione in fase di dichiarazione si fa con =. Infatti, se provate, vedrete che questo codice viene compilato correttamente:
Codice:
var
  n: integer = 5;

begin
  writeln(n);
end.
mentre questo no:
Codice:
var
  n: integer := 5; { non compila }

begin
  writeln(n);
end.
Ovviamente lo stesso vale per gli array. Il problema è che, a quanto ho avuto modo di vedere, questo tipo di inizializzazione non si può fare per gli attributi delle classi. Allora, una cosa sensata potrebbe essere inizializzarli tramite il costruttore, come nell'esempio seguente:
Codice:
{$mode objfpc}

Type
  MyClass = class
  private
    var
      value: integer; { attributo che voglio inizializzare }
  public
    constructor create(n: integer);
    procedure showValue;
  end;

constructor MyClass.create(n: integer);
begin
  value := n; { inizializza value con il valore di n  }
end;

procedure MyClass.showValue;
begin
  writeln(value);
end;

var
  MyClassInstance: MyClass;

begin
  MyClassInstance := MyClass.create(5);
  MyClassInstance.showValue; { stampa 5 }
end.
EDIT: se si dichiara un attributo come costante, è possibile (anzi obbligatorio) inizializzarlo in fase di dichiarazione. Quindi potresti risolvere dichiarando l'array TtbConti - a proposito, anch'io suggerirei di usare nomi più chiari - come const anziché var. Di seguito un esempio:
Codice:
{$mode objfpc}

Type
  MyClass = class
  private
    const
      TtbConti: array[0..13] of LongInt = (101001000, 101001997, // 1° range conti di Cassa (tabella movimgg)
                                           101001990, 101001999, // ultimo range conti di Cassa (tabella movimgg)
                                           102001000, 103999999, // 1° range conti di contropartita (tabella partmovv)
                                           105001000, 203999999, // 2° range conti di contropartita (tabella partmovv)
                                           205001000, 999999999, // ultimo range conti di contropartita (tabella partmovv)
                                           104001000, 104999000, // 1° range conti di contropartita (tabella prestmoom)
                                           204001000, 204999000);// ultimo range conti di contropartita (tabella prestmoom)
  public
    procedure showValues;
  end;

procedure MyClass.showValues;
var i: integer;
begin
  for i := low(TtbConti) to high(TtbConti) do
    writeln(TtbConti[i]);
end;

var
  MyClassInstance: MyClass;

begin
  MyClassInstance := MyClass.create;
  MyClassInstance.showValues;
end.
 
Ultima modifica:
  • Mi piace
Reazioni: Mursey

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
... lo stesso vale per gli array. Il problema è che, a quanto ho avuto modo di vedere, questo tipo di inizializzazione non si può fare per gli attributi delle classi. Allora, una cosa sensata potrebbe essere inizializzarli tramite il costruttore



Solo per autosdrammatizzare : Sempre più difficile, venghino signori, venghino.

Già, la mia testa scoppia. Ho bisogno di riprendermi un pò, anche perchè dovrò azzerare tutto quello fatto fino ad ora, nel tentativo di generare ciò che per me era un semplice array.
Infatti, a questo punto sono tentato di tornare alla mia matrice iniziale e di richiamare la classe che dovrà generarla all'interno di una procedura della classe Form1. Quest'ultima riflessione è nata perchè, ripensandoci, non ho bisogno, per questo programma, di renderla disponibile a tutte le procedure della Form1.
... :oogle:
semprecchè Free Pascal lo permetta.
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!