Autore Topic: Utilizzare i Puntatori con la funzione  (Letto 758 volte)

Offline jockerfox

  • Gambero
  • **
  • Post: 76
    • Mostra profilo
Utilizzare i Puntatori con la funzione
« il: 06 Febbraio 2012, 19:59:21 »
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:
Codice: gambas [Seleziona]
Public Sub Button8_Click()
  Dim iDatiElaborati As Integer
  iDatiElaborati = 2
  Print iDatiElaborati
  MDB_DBDati.wow(VarPtr(iDatiElaborati))
  Print iDatiElaborati
End


In un MODULO:
Codice: gambas [Seleziona]
Public Sub wow(iDatiElaborati As Pointer)
  Print iDatiElaborati
  iDatiElaborati = 100
  Print iDatiElaborati
End


Dove sbaglio?
:-)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #1 il: 06 Febbraio 2012, 20:48:02 »
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:

Codice: gambas [Seleziona]

' 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

« Ultima modifica: 17 Dicembre 2014, 15:39:26 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline jockerfox

  • Gambero
  • **
  • Post: 76
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #2 il: 06 Febbraio 2012, 22:21:12 »
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):
Codice: c [Seleziona]
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?
:-)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #3 il: 07 Febbraio 2012, 00:08:48 »
Mi faresti cortesemente lo stesso esempio ma con codice Gambas 3?

  ...dunque.... vediamo (con qualche nome cambiato):

Codice: gambas [Seleziona]

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ì:

Codice: gambas [Seleziona]

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:
Codice: gambas [Seleziona]

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/wiki/index.php/Variabili_di_tipo_Puntatore_e_loro_dereferenziazione
« Ultima modifica: 07 Luglio 2012, 23:48:36 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline jockerfox

  • Gambero
  • **
  • Post: 76
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #4 il: 07 Febbraio 2012, 15:46:27 »
Allora, ho trovato la soluzione chiedendo aiuto in un forum francese (http://gambasforge.org/sujet-4227-pointer-in-gambas-page-1.html)

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).

Codice: gambas [Seleziona]
Public Sub Button8_Click()
  Dim iDatiElaborati As Integer
  iDatiElaborati = 2
  Print "Inizio :" & iDatiElaborati

  MDB_DBDati.wow(ByRef iDatiElaborati)

  Print "Fine :" & iDatiElaborati
End


Codice: gambas [Seleziona]
Public Sub wow(ByRef iDatiElaborati As Integer)
  iDatiElaborati = 100
End


Chiaro il concetto, no? ;D
:-)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #5 il: 07 Febbraio 2012, 16:03:51 »
Chiaro il concetto, no? ;D

Molto interessante, ma... che c'entra questa soluzione con l'uso delle variabili tipo pointer As Pointer ?  ???
« Ultima modifica: 07 Febbraio 2012, 21:53:56 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline jockerfox

  • Gambero
  • **
  • Post: 76
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #6 il: 07 Febbraio 2012, 16:37:37 »
Citazione
Molto interessante, ma... che c'entra questa soluzione con l'uso dei Pointer ?
I Puntatori sono proprio quelli che ho riportato nella soluzione!
Ti riporto uno dei tanti siti dove spiegano i puntatori (che sia C, sia Java, sia Gambas, i puntatori esisteranno sempre!):
http://www.science.unitn.it/~fiorella/guidac/guidac025.html

Io, infatti, ho parlato di puntatori sin dall'inizio del mio thread:
Citazione
Devo modificare una variabile attraverso i puntatori..

Naturalmente, l'esempio che ho riportato in questo thread era un codice alternativo, cioè non è presente nel mio programma. Questo perché il fine era solo capire come utilizzare i puntatori in Gambas, ed una volta capito il concetto, poi puoi tranquillamente utilizzarlo dove e quando vuoi nei tuoi programmi...
I codice di esempio devono essere semplici per poter capire il concetto. Inutile presentare nel thread tutta la mia funzione! Non volevo alternative oppure che mi faceste voi il programma, volevo solo capire come funzionavano i puntatori; poi chi sa utilizzarli sa anche beneficiarli :P
:-)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #7 il: 07 Febbraio 2012, 16:51:50 »
I Puntatori sono proprio quelli che ho riportato nella soluzione!

Mi sono lasciato confondere dalla presenza nel tuo primo esempio dei termini: VarPtr e As Pointer. Ho erroneamente creduto che volessi lavorare insomma con quelli, con variabili di tipo Pointer.


Va be'...
« Ultima modifica: 07 Febbraio 2012, 22:03:20 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline jockerfox

  • Gambero
  • **
  • Post: 76
    • Mostra profilo
Re: Utilizzare i Puntatori con la funzione
« Risposta #8 il: 07 Febbraio 2012, 21:40:08 »
No problem  :ok:
L'importante che abbia riportato la soluzione in questo forum di modo che chi ha bisogno di utilizzare i puntatori ha la soluzione di come si deve procedere in Gambas 3.

Ciao a tutti ed al prossimo problema che mi si presenta  :2birre: ( ;D ;D)
:-)