....e la seconda matrice: clienti2$ = NEW String[num, 6]
Ricordo a me stesso che, avendo segnato 6, se il conteggio lo faccio partire da 0, si deve fermare a 5.
Relativamente agli array, secondo me, potevi scrivere:
Concordo con Picavbg: grossi problemi non ve ne sono.
Esempio simile al suo:
Public clienti1$ As String[]
Public clienti2$ As String[]
Public Sub Form_Open()
Dim num As Byte = 5
Dim j As Byte
Dim calculus As String
clienti1$ = New String[num]
clienti2$ = New String[num, 6]
' il totale delle unità di num non deve
' essere superiore a 5:
For num = 0 To 4
' il totale delle unità di j non deve
' essere superiore a 6:
For j = 0 To 5
clienti2$[num, j] = Str(num & " " & j)
Next
Next
For Each calculus In clienti2$
Print calculus
Next
End
Grazie per le risposte,
dunque, le dichiarazioni iniziali sono, e si vede nella citazione, all'inizio della main.class, mentre il resto del codice è inserito in un una procedura a se stante e non in un form open, ma questo non penso che possa rappresentare un problema, una diversità che invece può essere sostanziale è la dichiarazione dei puntatori: io infatti li avevo dichiarati integer mentre vedo che sono dichiarati come byte... in totale il mio codice è così:
PUBLIC clienti1$ AS String[] '##### 1° array dati clienti - Nome ditta
PUBLIC clienti2$ AS String[] '##### 2° array dati clienti - Dati ditta
PUBLIC tot_cli AS Integer '##### numero totali di clienti visualizzati
PUBLIC SUB _new()
assegnazioni()
END
PUBLIC SUB assegnazioni()
LETTURA_FILE_CLIENTI(tot_cli)
END
PUBLIC PROCEDURE LETTURA_FILE_CLIENTI(num AS Integer)
DIM clienti1_tmp$ AS String '##### Variabile navetta - Nome ditta
DIM clienti2_tmp$ AS NEW String[] '##### Array navetta - Dati ditta
DIM i AS Integer '##### puntatore numero del record
DIM j AS Integer '##### Puntatore numero del campo
DIM y AS Integer '##### Puntatore alternativo numero del record
DIM num_rec AS Integer '##### Numero totale dei record
clienti1$ = NEW String[num]
clienti2$ = NEW String[num, 6]
clienti2_tmp$ = NEW String[6]
FOR i = 0 TO num_rec - 1
clienti1$[y] = clienti1_tmp$
FOR j = 0 TO 5
clienti2$[y, j] = clienti2_tmp$[j]
NEXT
y = y + 1
NEXT
END
Questo è il codice interessato, non lo trovo tanto distante da quello che avete postato voi, il problema e che persiste il malfunzionamento che vi ho segnalato.
Ciao a tutti.
Vediamo un pò :coder: . Cominciamo dalla cosa più facile:
una diversità che invece può essere sostanziale è la dichiarazione dei puntatori: io infatti li avevo dichiarati integer mentre vedo che sono dichiarati come byte...
vuott ha dichiarato la variabile num come byte, probabilmente per risparmiare lo spazio da occupare in memoria o per sua abitudine. Il tipo variabile byte infatti occupa in memoria solamente 8 bit, ciioè un byte, mentre il tipo variabile integer occupa in memoria 16 bit, cioè 2 byte, ma non è obbligatorio utilizzare il tipo byte. Io, per mia abitudine, preferisco dichiarare gli indici degli array sempre come integer ed includo, come prilma lettera del nome variabile la "i", perchè così mi viene più facile e comodo riconoscerli.
Passiamo ora al codice:
clienti1$ = NEW String[num]
clienti2$ = NEW String[num, 6]
clienti2_tmp$ = NEW String[6]
FOR i = 0 TO num_rec - 1
clienti1$[y] = clienti1_tmp$
FOR j = 0 TO 5
clienti2$[y, j] = clienti2_tmp$[j]
NEXT
y = y + 1
NEXT
La riga 08 (clienti1$[y] = clienti1_tmp$ ) valorizza l'elemento y dell'array clienti1$ che è dimensionato ad 1 solo elemento, perchè num, nel codice che hai postato, non viene mai incrementato o riempito. Quindi, secondo quello che si legge, dopo il primo ciclo di loop, l'array è già finito e non può essere ulteriormente valorizzato. Probabilmente dovresti sostituire num con num_rec, ma anche quest'ultimo non riceve mai un valore.
PUBLIC SUB assegnazioni()
LETTURA_FILE_CLIENTI(tot_cli)
END
Secondo me, la SUB LETTURA_FILE_CLIENTI non dovrebbe essere una SUB, ma una Function in modo da farti ritornare anche il totale dei record contenuti nel file clienti:
PUBLIC FUNCTION LETTURA_FILE_CLIENTI(TotRec as integer)
Dim iToReCli as integer
' ?????, a proposito il File Clienti che file è? Un file di testo, o cos'altro?
......bla......bla......bla......
Return(iToReCli)
END
Vorrei dirti di più, ma ancora il tuo codice contiene applicati pochi concetti. Quindi partiamo da questo poco e piano piano costruiremo l'intero edificio.
Potresti, secondo me, prima di dedicarti alla gestione del file clienti, concentrarti sul codice scritto fino ad ora e fare funzionare quello. Allora potresti simulare che il file contenga, per esempio, 10 record e valorizzare quindi:
DIM num_rec AS Integer = 10 '##### Numero totale dei record
DIM num AS Integer = 10
Aggiusta il programma tenendo conto di quello che ci siamo detti per ora. Dopo averlo fatto funzionare così, passiamo, se vuoi, al trattamento del file clienti. ;)
:ciao: :ciao:
Effettivamente Picavbg ti devo delle spiegazioni supplimentari, perchè le tue obiezioni che hai mosso sono sensate, ma c'è perti della procedura che io non ho pubblicato che mutano del tutto la logica che tu presumi abbia il mio listato:
Tra la linea 27 e la linea 29 c'è una parte di codice molto significativa che va ad analizzare il file (li non si vedeva "CLIENTINEW.dat") ed alla fine la variabile num ha un valore ben determinato, nella prova che ho eseguito per esempio era 5; la variabile num_rec non deriva da un calcolo o da un conteggio, ma è scritto direttamente all'inizio del file e comunque è il totale dei record contenuti; num alla fine del codice che ti dicevo sopra contiene invece il totale dei record validi da visualizzare, e questa informazione è scritta nell'ultimo carattere di ogni record.
Dalla riga 33 in poi il codice legge nell variabile e negli array _tmp$ I record del file e poi li passa nella matrice definitiva solo se il record è valido e deve essere visualizzato, oltretutto non lo avevo postato ma nel codice esiste un secondo vettore serv$ che contiene sempre dati del file.
Per maggiore chiarezza ti posto quindi la routine completa:
PUBLIC PROCEDURE LETTURA_FILE_CLIENTI(num AS Integer)
'########################################################################## PROCEDURA LETTURA FILE ELENCO CLIENTI #####
DIM ch_file AS File '##### Identificatore del file
DIM clienti1_tmp$ AS String '##### Variabile navetta - Nome ditta
DIM clienti2_tmp$ AS NEW String[] '##### Array navetta - Dati ditta
DIM serv_tmp$ AS NEW String[] '##### Array navetta - Dati di servizio per il programma
DIM filler$ AS String '##### Lettura dati non usabili
DIM buffer$ AS String '##### Lettura diretta di un record
DIM visione$ AS String '##### Determinazione record da visualizzare
DIM i AS Integer '##### puntatore numero del record
DIM j AS Integer '##### Puntatore numero del campo
DIM y AS Integer '##### Puntatore alternativo numero del record
DIM num_rec AS Integer '##### Numero totale dei record
ch_file = OPEN _base & "CLIENTINEW.dat" FOR READ
INPUT #ch_file, filler$
INPUT #ch_file, num_rec
num = 0
y = 0
IF num_rec <> 0 THEN
FOR i = 1 TO num_rec
FOR j = 1 TO 13
LINE INPUT #ch_file, filler$
NEXT
visione$ = ESTRAI(filler$)
IF visione$ = "1" THEN
num = num + 1
END IF
NEXT
CLOSE #ch_file
clienti1$ = NEW String[num]
clienti2$ = NEW String[num, 6]
serv$ = NEW String[num, 6]
clienti2_tmp$ = NEW String[6]
serv_tmp$ = NEW String[6]
ch_file = OPEN _base &/ "CLIENTINEW.dat" FOR READ
INPUT #ch_file, filler$
INPUT #ch_file, filler$
FOR i = 0 TO num_rec - 1
LINE INPUT #ch_file, buffer$
clienti1_tmp$ = ESTRAI(buffer$)
FOR j = 0 TO 5
LINE INPUT #ch_file, buffer$
clienti2_tmp$[j] = ESTRAI(buffer$)
NEXT
FOR j = 0 TO 5
LINE INPUT #ch_file, buffer$
serv_tmp$[j] = ESTRAI(buffer$)
NEXT
IF serv_tmp$[5] = "1" THEN
clienti1$[y] = clienti1_tmp$
FOR j = 0 TO 5
clienti2$[y, j] = clienti2_tmp$[j]
NEXT
FOR j = 0 TO 5
serv$[y, j] = serv_tmp$[j]
NEXT
y = y + 1
END IF
NEXT
END IF
CLOSE #ch_file
END
Un'ultima cosa: riflettendo l'obiezione che mi muovi sul fatto di tramutare la procedure in function effettivamente è molto condivisibile, la variabile num all'esterno tot_cli in entrata non prevede valori ma solo essere dichiarata mentre restituisce poi il totali dei rekord visualizzati e quindi la function è senz'altro più che giustificata.
Ciao a tutti e saluti.
Io utilizzo raramente file sequenziali, per cui non ne conosco benissimo la metodologia più opportuna di gestione. Ho letto comunque la tua routine di lettura del file sequenziale ed ho notato che non contiene un controllo di sicurezza sull'esistenza del file, a meno che tu non lo faccia altrove.
Poi ho visto che apri più volte il file. Credo di capire che la prima volta lo fai, dopo avere valorizzato num-rec, solamente allo scopo di determinare il numero di record validi:
FOR i = 1 TO num_rec
FOR j = 1 TO 13 ==> 13 dovrebbero sono i campi interni a ciascun record, vero ?
LINE INPUT #ch_file, filler$
NEXT
visione$ = ESTRAI(filler$)
IF visione$ = "1" THEN
num = num + 1 ==> hai trovato un record valido
END IF
NEXT
CLOSE #ch_file
In realtà vi manca il controllo del fine-file (EOF), però se sei sicuro del contenuto di num-rec, va bene anche così.
Stabilito questo, perchè non mi pare sia il caso di approfondire, per ora la funzione di lettura file, ritornerei al problema di partenza:
For num = 0 To 4
' il totale delle unità di j non deve
' essere superiore a 6:
For j = 0 To 5
clienti2$[num, j] = Str(num & " " & j)
Next
Next
For Each calculus In clienti2$
Print calculus
Next
poi aggiungi:
il vettore clienti1$ è monodimensionale mentre clienti2$ è bidimensionale, ora il problema stà proprio in questa diversità: il primo funziona a dovere, mentre il secondo, a quanto pare, no! E se lo interrogo mi restituisce per i primi 5 elementi (num nell'elelaborazione di prova è pari a 5) il messaggio "Bad number of dimension" per i restanti "Out of bounds", quasi come se fosse impossibile dimensionare array pluridimensionali (francamente lo troverei un po strano).
nella documentazione ufficiale di Gambas l'errore "Bad number of dimension" fa presente che
Si tenta di accedere a un array, indicando una serie di indici diverso dal numero di dimensioni della matrice.
Cosa intendi per "se lo interrogo"?
For Each calculus In clienti2$ o altro?
Proviamo a farci dire dallo stesso Gambas quanti elementi sono dentro a clienti2$[num, j] subito dopo la sua creazione:
PUBLIC PROCEDURE LETTURA_FILE_CLIENTI(num AS Integer)
....bla....bla....bla....
clienti2$ = NEW String[num, 6]
print num
print clienti2$.count
....bla....bla....bla....
END
Se è come ti aspetti, dovresti anche dirmi come ottieni calculus.
:ciao:
Uhm... la variabile num deriva da tot_cli che è una variabile globale che viene dichiarata ma non settata in pratica num non riceve valori validi dalla chiamata della procedura, ma ne restituisce, ecco perché concordo con l'osservazione di Picavbg che mi rimarcava che era meglio che questa procedure fosse trasformata in una function.
:ciao:
scusami, ma mi sfugge, forse, qualcosa del ragionamento... però vedendo il codice continuo a non capire. :hard:
Allora... va be'... facciamo finta che ora hai trasformato la sub-routine da Procedure a Function... dunque sarebbe così:
PUBLIC FUNCTION LETTURA_FILE_CLIENTI(num AS Integer) As Integer
oh... però non mi pare che la sostanza cambi.... il che continua a significare che, non appena la procedura del programma passa a questa routine-Funzione, la variabile num viene riempita dall'intero passato da tot_cli (qualunque intero le passi).
Procedendo, però, il programma s'imbatte nella riga:
...qualunque cosa num contenesse, avendoglielo passato tot_cli, ora viene azzerato.
Domanda: ma se volevi semplicemente dichiarare il tipo di variabile nella Funzione, non era più corretto un:
...forse mi sfugge qualcosa ? :-\
:ciao:
@ Franco_da_vc:
Intendo dirti che facendo avvanzare il programma passo passo con il debugger ed evidenziando le variabil o gli arrays si ottiene come risposta il valore di ciò che si è evidenziato, evidenziando clienti1$ ottengo uno specchietto con i valori dei vari campi, mentre evidenziando clienti2$ ottengo per i primi 5 campi
"Bad number of dimension" e per i restanti campi Out of bounds
Aaaah! Ma quello specchietto in G2, il più delle volte, non funziona. :D Non tenerne conto e verifica piuttosto sempre con istruzioni print del tipo
FOR i = 0 TO num_rec - 1
print clienti1$[i]
FOR j = 0 TO 5
print clienti2$[i, j]
NEXT
NEXT
Se così funziona, non ti preoccupare, vai tranquillamente avanti, il programma non dovrebbe dare errori. ;)
Se dovesse dare errori allora converrà inquadrare il problema, focalizzando per bene il passo di programma in cui emergerà l'errore.
:ciao:
scusami, ma mi sfugge, forse, qualcosa del ragionamento... però vedendo il codice continuo a non capire. :hard:
Allora... va be'... facciamo finta che ora hai trasformato la sub-routine da Procedure a Function... dunque sarebbe così:
PUBLIC FUNCTION LETTURA_FILE_CLIENTI(num AS Integer)
oh... però non mi pare che la sostanza cambi.... il che continua a significare che, non appena la procedura del programma passa a questa routine-Funzione, la variabile num viene riempita dall'intero passato da tot_cli (qualunque intero le passi).
Procedendo, però, il programma s'imbatte nella riga:
Si, se però ti focalizzi sulla chiamata sarebbe plausibile questa sintassi:
tot_cli=LETTURA_FILE_CLIENTI()
Ragion per cui la dichiarazione diverrebbe:
PUBLIC FUNCTION LETTURA_FILE_CLIENTI()
...qualunque cosa num contenesse, avendoglielo passato tot_cli, ora viene azzerato.
Nel caso che ti ho illustrato io a questo punto avrebbe perfettamente senso sia la dichiarazione come variabile locale sia il settaggio a zero della stessa, considera anche che num non è un campo di comodo ma un contatore e chiaramente tranne casi particolari i contatori è buona norma settarli prima di porli in funzione, ma..........
Domanda: ma se volevi semplicemente dichiarare il tipo di variabile nella Funzione, non era più corretto un:
E proprio qui ho paura di aver dato per scontato qualcosa che non dovrei dare per scontato, nel basic da cui provengo le variabili di passaggio nelle proc e nelle function non dovevano essere dichiarate come variabili locali perché si sarebbe generato un errore sia a livello interprete che in fase di compilazione quindi una sintassi del genere non si poteva scrivere:
PUBLIC FUNCTION LETTURA_FILE_CLIENTI(num AS Integer)
Dim num As Integer
Ma qui, in gambas, è valida questa sintassi? Ho gia visto che le variabili che devono essere fatte ritornare nelle function:
qui in gambas devono essere dichiarate come locali nel precedente basic invece no!
Grazie! Ciao. :ciao:
sarebbe plausibile questa sintassi:
tot_cli=LETTURA_FILE_CLIENTI()
Ragion per cui la dichiarazione diverrebbe:
PUBLIC FUNCTION LETTURA_FILE_CLIENTI()
num = 0
Sì, così riesco a capire e mi è più chiaro.
Stando così, ossia senza dichiarazione della variabile num all'interno della routine-Function né nei parametri, mi lascia intendere che quella variabile è dichiarata come globale all'inizio, ovviamente.
Se è una Function, che appunto ritorna un valore, ovviamente va aggiunto dopo i parametri il tipo di valore che sarà restituito: As .....
E proprio qui ho paura di aver dato per scontato qualcosa...
PUBLIC FUNCTION LETTURA_FILE_CLIENTI(num AS Integer)
Dim num As Integer
Ma qui, in gambas, è valida questa sintassi?
E' una dichiarazione replicata, ripetuta: se la variabile la dichiari all'interno dei parametri della routine-Funzione, non la puoi dichiarare anche all'interno della routine medesima... la dichiari due volte !
Infatti, se fai una prova uscirà l'errore: "'num' already declared".
Ma dichiarando la variabile all'interno dei parametri, ovviamente sta a significare che la funzione riceve un valore da quella variabile. Valore che poi la Funzione avrà il compito di manipolare.
Ad ogni modo, se tu vuoi che restituisca il valore di num:
...
' questa istruzione non passa alcun valore alla Funzione chiamata:
tot_cli=LETTURA_FILE_CLIENTI()
...
End
PUBLIC FUNCTION LETTURA_FILE_CLIENTI() As Integer ' la Funzione non riceve alcun valore dalla funzione principale chiamante
Dim num As Integer
' adottiamo il tuo giudizio: "è buona norma settarli prima di porli in funzione"
num = 0
....etc
....etc
....etc
Return num
End
qui in gambas devono essere dichiarate come locali nel precedente basic invece no!
...non in senso assoluto. Prova infatti questo:
a As Integer = 10
Public Sub Button1_Click()
Dim o As Integer
o = alibaba()
Print o
End
Public Function alibaba() As Integer
a = a + 10
Return a
End
...anche se, però, effettivamente - seppur non dia errore - mi sembra avere poco senso utilizzare una Funzione ed una variabile globale... :rolleyes:
Ciao a tutti,
ora il tutto funziona, forse a qualcuno questa soluzione non piacerà, ma e molto funzionale, semplicemente nella dichiarazione della procedura non passo alcun parametro
Public Procedure LETTURA_FILE_CLIENTI()
la variaqbile num la dichiaro come locale nella procedura stessa mentre la variabile tot_cli è una varibile globale ed alla fine della procedura passo il valore di num in tot_cli
in modo da lavorare tranquillamente in locale e solo alla fine passare il valore ottenuto nella variabile da me fissata.
Con questo messaggio termino i miei post in questa area perchè avendo ora Gasmbas 3 inserirò i miei post nell'area pertinente.
Ciao a tutti