Ciao a tutti !
Devo modificare una variabile attraverso i puntatori.. ma mi manca il nesso (barlumi del C) del benedetto asterisco * alla variabile...
In pratica la mia domanda si riduce ad un semplice "Ma in gambas3 come si fa?"
Ecco codice:
In FMain:
Public Sub Button8_Click()
Dim iDatiElaborati As Integer
iDatiElaborati = 2
Print iDatiElaborati
MDB_DBDati.wow(VarPtr(iDatiElaborati))
Print iDatiElaborati
End
In un MODULO:
Public Sub wow(iDatiElaborati As Pointer)
Print iDatiElaborati
iDatiElaborati = 100
Print iDatiElaborati
End
Dove sbaglio?
La funzione VarPtr(....), utilizzabile solo in Gambas-3, "restituisce l'indirizzo in memoria di una variabile o, in altre parole, il puntatore alla variabile stessa - è ciò che dice lo stesso nome: VAR-PTR, "Variable pointer" ("puntatore alla variabile")".
Esempio pratico:
Funzione originaria di C:
int snd_seq_open (snd_seq_t * *seqp, const char *name, int streams, int mode)
che viene dichiarata in Gambas con Extern:
PRIVATE EXTERN snd_seq_open(seq AS Pointer, name as String, streams as Integer, mode as Integer) as Integer
...per essere richiamata espressamente in una routine quando serve:
Public sub.....
Dim err As Integer
Dim handle AS Pointer
err = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_DUPLEX, 0)
utilizziamo VarPtr(pointer As Pointer) AS Pointer, il quale passa l'indirizzo del puntatore alla variabile "handle"; esso ritorna cioè un puntatore alla variabile "handle".
Oppure un altro esempio:
' qualsiasi_funzione(pnt1* *pnt2) ...anche qui la funzione scritta in C vuole che le sia passato un puntatore ad un puntatore
' dichiariamo la funzione esterna a Gambas con Extern:
Private EXTERN qualsiasi_funzione(pnt As Pointer)
Public Sub quello_che_è(aPnt As Pointer)
' passiamo una variabile puntatore ad un puntatore alla funzione d'esempio:
qualsiasi_funzione(VarPtr(aPnt))
End
La mia funzione Button8_Click non deve restituire niente, questo perché nel mio codice del programma tale funzione deve solo ed esclusivamente modificare diverse variabili che gli passo. Ovvio che potrei optare per una variabile globale, ma non è quello che vorrei...
Ti faccio un esempio in C (esempio classico di uno swap):
void swap(int *a, int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
main()
{
int a=10,b=20;
swap(&a,&b);
..ecco che qua mi ritrovo le due variabili modificate per effetto di swap con l'uso dei puntatori
}
Mi faresti cortesemente lo stesso esempio ma con codice Gambas 3?
Mi faresti cortesemente lo stesso esempio ma con codice Gambas 3?
...dunque.... vediamo (con qualche nome cambiato):
Public Sub Button1_Click() ' al clic si scatena... l'inferno !
Dim a, b As Integer
Dim aP, bP As Pointer
' i valori Integer di partenza sono:
a = 10
b = 20
' ...e li mostriamo in console:
Print "a iniziale = "; a, "b iniziale = "; b
' poniamo due puntatori in memoria alle due variabili Integer.
' ap e bP non contengono gli interi, bensi gli indirizzi di memoria ove andare a "raccogliere" i due valori Integer:
aP = VarPtr(a)
bP = VarPtr(b)
' passiamo i valori pointer alla subroutine "swp":
swp(aP, bP)
End
Public Sub swp(aPoi As Pointer, bPoi As Pointer)
Dim aStream, bStream As Stream
Dim tempus, aInt, bInt, a, b As Integer
Dim bTerPointer As Pointer
' dereferenziamo il pointer mediante l'uso dei Memory-Stream:
aStream = Memory aPoi For Read
' e lo andiamo a leggere:
Read #aStream, aInt
' l'intero viene trasferito nella variabile Integer "tempus",
' (nel tuo esempio in C siamo al punto: temp=*a; ):
tempus = aInt
aPoi = bPoi ' (qui siamo al punto: *a=*b; )
' dereferenziamo nuovamente il pointer aPoi,
' (ma questa volta senza Memory-Stream,
' bensì con l'apposita funzione " Int@ ")
' ci servirà per la verifica finale:
aInt = Int@(aPoi)
bTerPointer = VarPtr(tempus) ' (qui siamo al punto: *b=temp; )
'dereferenziamo l'altro pointer per la verifica finale:
bInt = Int@(bTerPointer)
a = aInt
b = bInt
' verifichiamo l'inversione, mostrandola in console:
Print "a finale = "; a, "b finale = "; b
End
....alla fine ho coerentemente i valori invertiti. :-[
Se vuoi utilizzare una Funzione (come è nell'esempio originario in C ), e - come hai detto - non vuoi usare variabili globali, allora si potrebbe fare così:
Public Sub Button1_Click()
Dim a, b As Integer
Dim aP, bP As Pointer
Dim abPoi As Pointer[]
Dim aStream, bStream As Stream
' i valori Integer di partenza sono:
a = 10
b = 20
' ...e li mostriamo in console:
Print "a iniziale = "; a, "b iniziale = "; b
' poniamo due puntatori in memoria alle due variabili Integer.
' ap e bP non contengono gli interi, bensi gli indirizzi di memoria ove andare a "raccogliere" i due valori Integer:
aP = VarPtr(a)
bP = VarPtr(b)
' Passiamo i valori pointer alla Funzione "swp", affinché li elabori.
' La variabile "abPoi" conterrà i valori di elaborazione ritornati da quella Funzione:
abPoi = swp(aP, bP)
' dereferenziamo mediante l'uso dei Memory-Stream il primo pointer,
' restituito dalla Funzione, per la verifica finale:
aStream = Memory abPoi[0] For Read
' e lo andiamo a leggere:
Read #aStream, a
' dereferenziamo il secondo pointer, restituito dalla Funzione, per la verifica finale,
' questa volta però con la funzione specifica " Int@ " :
b = Int@(abPoi[1])
' verifichiamo l'inversione, mostrandola in console:
Print "a finale = "; a, "b finale = "; b
End
Public Function swp(aPoi As Pointer, bPoi As Pointer) As Pointer[]
Dim aStream, bStream As Stream
Dim tempus, aInt, bInt, a, b As Integer
Dim bTerPointer As Pointer
Dim doppioPoin As New Pointer[]
' dereferenziamo il pointer mediante l'uso dei Memory-Stream:
aStream = Memory aPoi For Read
' e lo andiamo a leggere:
Read #aStream, aInt
' l'intero viene trasferito nella variabile Integer "tempus",
' (nel tuo esempio in C siamo al punto: temp=*a; ):
tempus = aInt
aPoi = bPoi ' (qui siamo al punto: *a=*b; )
bTerPointer = VarPtr(tempus) ' (qui siamo al punto: *b=temp; )
doppioPoin.Add(aPoi)
doppioPoin[0] = aPoi
doppioPoin.Add(bTerPointer)
doppioPoin[1] = bTerPointer
' restituiamo i due valori Pointer, contenuti in doppioPoin, alla routine principale chiamante:
Return doppioPoin
End
....alla fine ho coerentemente i valori invertiti. :)
Ah, scusami, riguardo invece al tuo esempio iniziale:
Public Sub Button8_Click()
Dim iDatiElaborati As Integer
Dim datiPntr As Pointer
iDatiElaborati = 2
' mostriamo il valore Integer di partenza
Print iDatiElaborati
' poniamo nel pointer "datiPntr" l'indirizzo che punta alla variabile Integer "iDatiElaborati":
datiPntr = VarPtr(iDatiElaborati)
' passiamo alla routine del modulo l'indirizzo contenuto nel Pointer:
MDB_DBDati.wow(datiPntr)
End
Public Sub wow(idP As Pointer) ' qui siamo nel MODULO: MDB_DBDati
Dim a, iDatiElaborati As Integer
Dim aStream As Stream
' dereferenziamo il pointer con l'uso di specifica funzione:
iDatiElaborati = Int@(idP)
' verifichiamo (avremo coerentemente l'intero di partenza),
' e lo mostriamo in console:
Print "1° valore nel modulo = "; iDatiElaborati
' ...poi tu hai voluto caricare nella variabile Integer un altro valore:
iDatiElaborati = 100
' e lo mostriamo in console:
Print "2° valore nel modulo = "; iDatiElaborati
End
In sostanza, dopo aver posto con VarPtr in un puntatore l'indirizzo di una variabile, per estrarre il valore contenuto nella variabile puntata dal puntatore, ossia per deferenziare il pointer puoi usare i Memory-Stream (soprattutto se è stata utilizzata una zona riservata di memoria con la funzione alloc) in lettura, oppure più brevemente una specifica funzione (Int@, Byte@, Float@, etc, a seconda del tipo ovviamente) che restituisca il valore memorizzato all'indirizzo specificato dal Puntatore.
Sui puntatori vedere anche qui:
http://www.gambas-it.org/smf/index.php?topic=586.0 (http://www.gambas-it.org/smf/index.php?topic=586.0)
http://www.gambas-it.org/wiki/index.php/Variabili_di_tipo_Puntatore_e_loro_dereferenziazione (http://www.gambas-it.org/wiki/index.php/Variabili_di_tipo_Puntatore_e_loro_dereferenziazione)
Allora, ho trovato la soluzione chiedendo aiuto in un forum francese (http://gambasforge.org/sujet-4227-pointer-in-gambas-page-1.html (http://LINK))
La soluzione consiste nell'usare la keyworld "byref" !!!
Ecco la soluzione al mio problema (che naturalmente, ripeto, il codice riportato qua non è quello vero nel mio programma perché è molto più ben complesso e lavoro su i database; il codice è volutamente semplice perché una volta capito il meccanismo, possiamo adeguarlo alle nostre esigenze).
Public Sub Button8_Click()
Dim iDatiElaborati As Integer
iDatiElaborati = 2
Print "Inizio :" & iDatiElaborati
MDB_DBDati.wow(ByRef iDatiElaborati)
Print "Fine :" & iDatiElaborati
End
Public Sub wow(ByRef iDatiElaborati As Integer)
iDatiElaborati = 100
End
Chiaro il concetto, no? ;D