Differenze tra le versioni di "Passaggio di un argomento per 'indirizzo' ad una Funzione"

Da Gambas-it.org - Wikipedia.
 
(10 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
Il passaggio come argomento ad una Funzione mediante un ''Puntatore'' dell'indirizzo di memoria di una variabile automatica ovvero di un'area di memoria appositamente allocata, viene definito "''passaggio per Indirizzo''". <SUP>&#91;[[#Note|Nota 1]]&#93;</sup>
+
Il passaggio come argomento ad una Funzione mediante un ''Puntatore'' dell'indirizzo di memoria di una variabile automatica ovvero di un'area di memoria appositamente allocata, viene definito "''passaggio per Indirizzo''". <SUP>&#91;[[#Note|Nota 1]]&#93;</sup> <SUP>&#91;[[#Note|Nota 2]]&#93;</sup>
<BR>Per passare l'<I>Indirizzo</i> di memoria di una variabile, bisognerà servirsi della funzione ''VarPtr( )''.
+
<BR>Per passare l'<I>Indirizzo</i> di memoria di una variabile, bisognerà servirsi della funzione "VarPtr()".
<BR>Per passare, invece, l'<I>Indirizzo</i> di memoria di un'area di memoria appositamente allocata mediante la funzione ''Alloc( )'', si passerà come argomento la variabile di tipo ''Puntatore'' che punta alla predetta area di memoria riservata.
+
<BR>Per passare, invece, l'<I>Indirizzo</i> di memoria di un'area di memoria appositamente allocata mediante la funzione "Alloc()", si passerà come argomento la variabile di tipo ''Puntatore'' che punta alla predetta area di memoria riservata.
 +
 
 +
Analogamente il passaggio per "''Indirizzo'' " avviene anche usando i "Vettori" e le "Strutture" (essendo le relative variabili nient'altro che Puntatori alle aree di memoria di tali Oggetti), nonché le variabili che identificano gli "Oggetti" quali istanze di Classi.
  
 
Il passaggio degli argomenti per ''indirizzo'' consente di eliminare l'istruzione ''Return'', e di ritornare, così, il valore dalla Funzione ''chiamata'' alla routine principale ''chiamante'' attraverso il parametro medesimo di tipo ''Puntatore'' della Funzione.
 
Il passaggio degli argomenti per ''indirizzo'' consente di eliminare l'istruzione ''Return'', e di ritornare, così, il valore dalla Funzione ''chiamata'' alla routine principale ''chiamante'' attraverso il parametro medesimo di tipo ''Puntatore'' della Funzione.
<BR>Per scrivere in uno dei parametri di tipo ''Puntatore'' della Funzione chiamata il risultato finale delle operazioni compiute dalla Funzione medesima, bisognerà utilizzare i ''Memory Stream''.
+
<BR>Avere un riferimento all'oggetto è molto utile in fase di passaggio tramite parametri tra un Metodo e l'altro. La modifica dell'oggetto fa sì che venga mantenuta in uscita dal Metodo, eliminando così l'obbligo del ritorno di un valore.
  
 +
E' appena il caso di ricordare che il passaggio di valori per "''Indirizzo'' " a una sotto-procedura/funzione, non crea una copia dell'Oggetto, o comunque del tipo, passato, come avviene invece nel passaggio per "''Valore'' ", ove si va ad occupare un'altra area di memoria (per generare la copia) di dimensioni pari a quella occupata dall'Oggetto (o dal tipo di valore) passato.
 +
<BR>Va da sé che con il passaggio per "''Valore'' ", avendo due copie uguali, avremo due indirizzi di memoria che si riferiscono ovviamente a due aree di memoria riservate automaticamente di uguale dimensione, ...e quindi un consumo doppio delle risorse (ossia della memoria necessaria per il passaggio dei dati).
 +
<BR>Il passaggio per "''Indirizzo'' " fa in modo che la modifica avvenga direttamente all'indirizzo di memoria dell'Oggetto (o del tipo di valore) passato evitando così la creazione di una copia e l'occupazione di altra memoria per il medesimo dato da passare.
  
===Esempi pratici===
+
Per scrivere in uno dei parametri di tipo ''Puntatore'' della Funzione chiamata il risultato finale delle operazioni compiute dalla Funzione medesima, bisognerà utilizzare - come sappiamo - i ''[[Definizione_ed_uso_dei_Memory_Stream|Memory Stream]]''.
Esempio di ''passaggio per Indirizzo'' di una variabile dichiarata come tipo ''Intero'':
+
 
 +
 
 +
===Passaggio per ''Indirizzo'' usando variabili di tipo ''Puntatore''===
 +
Esempio di ''passaggio per Indirizzo'' dell'indirizzo di memoria di una variabile dichiarata come tipo ''Intero'', usando la funzione "VarPtr()":
 
  '''Public''' Sub Main()
 
  '''Public''' Sub Main()
 
    
 
    
  Dim ptr As Pointer
+
  Dim i As Integer
  Dim c As Integer
 
 
    
 
    
 
  <FONT Color=gray>' ''Assegnamo un valore iniziale alla variabile di tipo "Intero":''</font>
 
  <FONT Color=gray>' ''Assegnamo un valore iniziale alla variabile di tipo "Intero":''</font>
   c = 1000
+
   i = 1000
 
      
 
      
 
  <FONT Color=gray>' ''Passiamo mediante la funzione "VarPtr()" l'indirizzo di memoria della variabile di tipo "Intero":''</font>
 
  <FONT Color=gray>' ''Passiamo mediante la funzione "VarPtr()" l'indirizzo di memoria della variabile di tipo "Intero":''</font>
   Funzione(VarPtr(c))
+
   Funzione(VarPtr(i))
 
      
 
      
   Print c
+
   Print i
 
    
 
    
 
  '''End'''
 
  '''End'''
 
 
   
 
   
 
  '''Private''' Function Funzione(p As Pointer)
 
  '''Private''' Function Funzione(p As Pointer)
Riga 30: Riga 36:
 
      
 
      
 
  <FONT Color=gray>' ''Otteniamo una variabile "Stream" dal "Puntatore" mediante i "Memory Stream":''</font>
 
  <FONT Color=gray>' ''Otteniamo una variabile "Stream" dal "Puntatore" mediante i "Memory Stream":''</font>
  st = Memory p For Write
+
  st = Memory p For Write
 
  <FONT Color=gray>' ''Scriviamo nel flusso dell'area di memoria, puntata dalla variabile "p", il risultato di una moltiplicazione:''</font>
 
  <FONT Color=gray>' ''Scriviamo nel flusso dell'area di memoria, puntata dalla variabile "p", il risultato di una moltiplicazione:''</font>
  Write #st, Int@(p) * 1000 As Integer
+
  Write #st, Int@(p) * 1000 As Integer
 
  <FONT Color=gray>' ''Chiudiamo il flusso di dati verso l'area di memoria:''</font>
 
  <FONT Color=gray>' ''Chiudiamo il flusso di dati verso l'area di memoria:''</font>
  st.Close
+
  st.Close
 
    
 
    
 
  '''End'''
 
  '''End'''
  
  
 
+
Esempio di ''passaggio per Indirizzo'' di una variabile di tipo ''Puntatore'' che punta ad una piccola area di memoria opportunamente allocata con la funzione "''Alloc()''":
Esempio di ''passaggio per Indirizzo'' di una variabile di tipo ''Puntatore'' che punta ad una piccola area di memoria opportunamente allocata:
 
 
  '''Public''' Sub Main()
 
  '''Public''' Sub Main()
 
    
 
    
  Dim p As Pointer
+
  Dim p As Pointer
 
    
 
    
 
  <FONT Color=gray>' ''Allochiamo un'area di memoria:''</font>
 
  <FONT Color=gray>' ''Allochiamo un'area di memoria:''</font>
Riga 54: Riga 59:
 
   Print Byte@(p)
 
   Print Byte@(p)
 
      
 
      
  <FONT Color=gray>' ''Liberiamo la memoria precedentemente allocata:''</font>
+
  <FONT Color=gray>' ''Libera la memoria precedentemente allocata e si assicura che il "Puntatore" non punti a un indirizzo di memoria rilevante:''</font>
 
   Free(p)
 
   Free(p)
 
 
<FONT Color=gray>' ''Ci assicuriamo che la variabile di tipo "Puntatore" non punti più ad alcuna cella di memoria:''</font>
 
 
   p = 0
 
   p = 0
 
    
 
    
 
  '''End'''
 
  '''End'''
 
 
   
 
   
 
  '''Private''' Function Funzione(po As Pointer)
 
  '''Private''' Function Funzione(po As Pointer)
 
    
 
    
  Dim st As Stream
+
  Dim st As Stream
 
+
 
  <FONT Color=gray>' ''Creiamo una variabile di tipo "Stream" mediante i "Memory Stream", al fine di poter scrivere all'interno dell'area di memoria allocata:''</font>
 
  <FONT Color=gray>' ''Creiamo una variabile di tipo "Stream" mediante i "Memory Stream", al fine di poter scrivere all'interno dell'area di memoria allocata:''</font>
 
   st = Memory po For Write
 
   st = Memory po For Write
Riga 74: Riga 76:
 
    
 
    
 
  <FONT Color=gray>' ''Chiudiamo il flusso di dati:''</font>
 
  <FONT Color=gray>' ''Chiudiamo il flusso di dati:''</font>
    st.Close
+
  st.Close
 
    
 
    
 
  '''End'''
 
  '''End'''
  
 +
 +
===Passaggio per ''Indirizzo'' usando variabili di tipo ''vettoriale''===
 +
Di seguito un semplice esempio usando un vettore, adeguatamente creato nella funzione principale chiamante:
 +
  '''Public''' Sub Main()
 +
 
 +
  Dim vettore As New Integer[4]
 +
  Dim i As Integer
 +
 +
  For i = 0 To vettore.Max
 +
      vettore[i] = i + 1
 +
  Next
 +
 
 +
  Funzione(vettore)  <Font Color=gray>' ''Passaggio per "Indirizzo"''</font>
 +
 
 +
  For Each i in vettore
 +
    Print i
 +
  Next
 +
 
 +
  '''End'''
 +
 
 +
  '''Private''' Function Funzione(ii As Integer[])
 +
 
 +
  Dim i As Integer
 +
 
 +
  For i = 0 To ii.Max
 +
      ii[i] = ii[i] * 100
 +
  Next
 +
 
 +
  '''End'''
 +
 +
 +
===Passaggio per ''Indirizzo'' usando variabili di tipo ''Struttura''===
 +
Di seguito un semplice esempio usando una variabile di tipo ''Struttura'', adeguatamente creata nella funzione principale chiamante:
 +
  Public Struct STRUTTURA
 +
    b As Byte
 +
    c As Short
 +
    i As Integer
 +
  End Struct
 +
 
 +
 
 +
  '''Public''' Sub Main()
 +
 
 +
  Dim stra As New STRUTTURA
 +
 
 +
  With stra
 +
    .b = 100
 +
    .c = 2000
 +
    .i = 30000
 +
  End With
 +
 
 +
  Funzione(stra)  <Font Color=gray>' ''Passaggio per "Indirizzo"''</font>
 +
 
 +
  With stra
 +
    Print .b
 +
    Print .c
 +
    Print .i
 +
  End With
 +
 
 +
  '''End'''
 +
 +
  '''Private''' Function Funzione(st As STRUTTURA)
 +
 
 +
  With st
 +
    .b = st.b * 2
 +
    .c = st.c * 2
 +
    .i = st.i * 2
 +
  End With
 +
 
 +
  '''End'''
  
  
  
 
=Note=
 
=Note=
[1] Su questo argomento vedere anche la seguente pagina della WIKI:
+
[1] In Gambas elementi complessi come gli ''Oggetti'' vengono sempre passati come ''Riferimento'', ovvero l'indirizzo di memoria in cui si trovano. Riguardo invece alle normali variabili di tipi base (Byte, Short, Integer/String/Long ecc.) queste non sono Oggetti ma "valori" ben precisi, che vengono passati come "Valore", e non come locazione di memoria. Questa differenza implica che, per quanto riguarda gli Oggetti, ogni modifica al suo contenuto viene mantenuta, mentre per le variabili, dato che ne viene passata una copia del valore, queste vengono perse all'uscita della stessa funzione che le gestisce.
http://www.gambas-it.org/wiki/index.php?title=Scrivere_una_Funzione#Passaggio_per_indirizzo
+
<BR>Il concetto di parametro passato "per Riferimento" (ByRif) in Gambas, fa sì che la funzione prende in ingresso l'indirizzo di memoria in cui è depositato il valore, e non ne crea una copia. Ciò consente, come per gli Oggetti, di ritrovarsi la variabile di base modificata anche dopo l'uscita dalla funzione.
 +
 
 +
[2] Su questo argomento vedere anche la seguente pagina della WIKI:
 +
[http://www.gambas-it.org/wiki/index.php?title=Scrivere_una_Funzione#Passaggio_per_indirizzo Passaggio per indirizzo]

Versione attuale delle 20:23, 1 ott 2022

Il passaggio come argomento ad una Funzione mediante un Puntatore dell'indirizzo di memoria di una variabile automatica ovvero di un'area di memoria appositamente allocata, viene definito "passaggio per Indirizzo". [Nota 1] [Nota 2]
Per passare l'Indirizzo di memoria di una variabile, bisognerà servirsi della funzione "VarPtr()".
Per passare, invece, l'Indirizzo di memoria di un'area di memoria appositamente allocata mediante la funzione "Alloc()", si passerà come argomento la variabile di tipo Puntatore che punta alla predetta area di memoria riservata.

Analogamente il passaggio per "Indirizzo " avviene anche usando i "Vettori" e le "Strutture" (essendo le relative variabili nient'altro che Puntatori alle aree di memoria di tali Oggetti), nonché le variabili che identificano gli "Oggetti" quali istanze di Classi.

Il passaggio degli argomenti per indirizzo consente di eliminare l'istruzione Return, e di ritornare, così, il valore dalla Funzione chiamata alla routine principale chiamante attraverso il parametro medesimo di tipo Puntatore della Funzione.
Avere un riferimento all'oggetto è molto utile in fase di passaggio tramite parametri tra un Metodo e l'altro. La modifica dell'oggetto fa sì che venga mantenuta in uscita dal Metodo, eliminando così l'obbligo del ritorno di un valore.

E' appena il caso di ricordare che il passaggio di valori per "Indirizzo " a una sotto-procedura/funzione, non crea una copia dell'Oggetto, o comunque del tipo, passato, come avviene invece nel passaggio per "Valore ", ove si va ad occupare un'altra area di memoria (per generare la copia) di dimensioni pari a quella occupata dall'Oggetto (o dal tipo di valore) passato.
Va da sé che con il passaggio per "Valore ", avendo due copie uguali, avremo due indirizzi di memoria che si riferiscono ovviamente a due aree di memoria riservate automaticamente di uguale dimensione, ...e quindi un consumo doppio delle risorse (ossia della memoria necessaria per il passaggio dei dati).
Il passaggio per "Indirizzo " fa in modo che la modifica avvenga direttamente all'indirizzo di memoria dell'Oggetto (o del tipo di valore) passato evitando così la creazione di una copia e l'occupazione di altra memoria per il medesimo dato da passare.

Per scrivere in uno dei parametri di tipo Puntatore della Funzione chiamata il risultato finale delle operazioni compiute dalla Funzione medesima, bisognerà utilizzare - come sappiamo - i Memory Stream.


Passaggio per Indirizzo usando variabili di tipo Puntatore

Esempio di passaggio per Indirizzo dell'indirizzo di memoria di una variabile dichiarata come tipo Intero, usando la funzione "VarPtr()":

Public Sub Main()
 
  Dim i As Integer
 
' Assegnamo un valore iniziale alla variabile di tipo "Intero":
  i = 1000
   
' Passiamo mediante la funzione "VarPtr()" l'indirizzo di memoria della variabile di tipo "Intero":
  Funzione(VarPtr(i))
   
  Print i
  
End

Private Function Funzione(p As Pointer)
 
 Dim st As Stream
    
' Otteniamo una variabile "Stream" dal "Puntatore" mediante i "Memory Stream":
 st = Memory p For Write
' Scriviamo nel flusso dell'area di memoria, puntata dalla variabile "p", il risultato di una moltiplicazione:
 Write #st, Int@(p) * 1000 As Integer
' Chiudiamo il flusso di dati verso l'area di memoria:
 st.Close
 
End


Esempio di passaggio per Indirizzo di una variabile di tipo Puntatore che punta ad una piccola area di memoria opportunamente allocata con la funzione "Alloc()":

Public Sub Main()
 
  Dim p As Pointer
 
' Allochiamo un'area di memoria:
  p = Alloc(SizeOf(gb.Byte), 2)
   
' Passiamo la viariabile di tipo "Puntatore" alla Funzione secondaria:
  Funzione(p)
   
' Dereferenziamo il "Puntatore", per vedere il valore presente nel primo byte dell'area riservata puntata:
  Print Byte@(p)
   
' Libera la memoria precedentemente allocata e si assicura che il "Puntatore" non punti a un indirizzo di memoria rilevante:
  Free(p)
  p = 0
  
End

Private Function Funzione(po As Pointer)
 
  Dim st As Stream

' Creiamo una variabile di tipo "Stream" mediante i "Memory Stream", al fine di poter scrivere all'interno dell'area di memoria allocata:
  st = Memory po For Write
  
' Scriviamo un valore di tipo "Byte" nel primo byte dell'area di memoria allocata:
  Write #st, 199 As Byte
  
' Chiudiamo il flusso di dati:
  st.Close
  
End


Passaggio per Indirizzo usando variabili di tipo vettoriale

Di seguito un semplice esempio usando un vettore, adeguatamente creato nella funzione principale chiamante:

 Public Sub Main()
 
  Dim vettore As New Integer[4]
  Dim i As Integer

  For i = 0 To vettore.Max
     vettore[i] = i + 1
  Next
  
  Funzione(vettore)   ' Passaggio per "Indirizzo"
  
  For Each i in vettore
    Print i
  Next
  
 End
 
 Private Function Funzione(ii As Integer[])
  
  Dim i As Integer
 
  For i = 0 To ii.Max
     ii[i] = ii[i] * 100
  Next
  
 End


Passaggio per Indirizzo usando variabili di tipo Struttura

Di seguito un semplice esempio usando una variabile di tipo Struttura, adeguatamente creata nella funzione principale chiamante:

 Public Struct STRUTTURA
   b As Byte
   c As Short
   i As Integer
 End Struct
 
 
 Public Sub Main()
 
  Dim stra As New STRUTTURA
  
  With stra
    .b = 100
    .c = 2000
    .i = 30000
  End With
  
  Funzione(stra)   ' Passaggio per "Indirizzo"
  
  With stra
    Print .b
    Print .c
    Print .i
  End With
  
 End

 Private Function Funzione(st As STRUTTURA)
  
  With st
    .b = st.b * 2
    .c = st.c * 2
    .i = st.i * 2
  End With
  
 End


Note

[1] In Gambas elementi complessi come gli Oggetti vengono sempre passati come Riferimento, ovvero l'indirizzo di memoria in cui si trovano. Riguardo invece alle normali variabili di tipi base (Byte, Short, Integer/String/Long ecc.) queste non sono Oggetti ma "valori" ben precisi, che vengono passati come "Valore", e non come locazione di memoria. Questa differenza implica che, per quanto riguarda gli Oggetti, ogni modifica al suo contenuto viene mantenuta, mentre per le variabili, dato che ne viene passata una copia del valore, queste vengono perse all'uscita della stessa funzione che le gestisce.
Il concetto di parametro passato "per Riferimento" (ByRif) in Gambas, fa sì che la funzione prende in ingresso l'indirizzo di memoria in cui è depositato il valore, e non ne crea una copia. Ciò consente, come per gli Oggetti, di ritrovarsi la variabile di base modificata anche dopo l'uscita dalla funzione.

[2] Su questo argomento vedere anche la seguente pagina della WIKI: Passaggio per indirizzo