Conoscere con i Puntatori i valori contenuti in un vettore

Da Gambas-it.org - Wikipedia.

Un vettore è sostanzialmente un Oggetto, nella cui area di memoria sono contenuti dati del medesimo tipo, ossia che occupano la medesima quantità di memoria (tutti Byte, o tutti Short, o tutti Integer, oppure tutti appartenenti ad un medesimo tipo di Oggetti e così via).

I vettori mettono a disposizione, fra l'altro, la proprietà .Data, che restituisce un Puntatore (ossia l'indirizzo di memoria) ai dati contenuti dal vettore medesimo.

E' possibile spostandoci lungo l'area di memoria puntata da tale Puntatore secondo la quantità di memeoria occupata dal tipo di vettore (Byte[], Short[], etc), leggere i valori contenuti dalla variabile vettoriale.


Conoscere con il Puntatore i valori di un vettore del tipo numerico

In un array del tipo nativo numerico i valori in esso contenuti sono allocati sin dal primo byte dell'area di memoria del vettore medesimo. I valori ovviamente sono posti ad una distanza l'uno dall'altro sulla base della quantità di memoria occupata dal tipo di valore.

Mostriamo un semplice esempio con un vettore di tipo Integer():

Public Sub Main()
 
 Dim ii As Integer[] = [2, 22, 222, 2222, 22222, 222222, 2222222]
 Dim p As Pointer
 Dim b As Byte
   
  p = ii.Data
   
  For b = 0 To ii.Max
' Dereferenziamo il puntatore per ottenere il valore contenuto dalla locazione di memoria puntata:
    Print b;; Int@(p)
' Trattandosi di un vettore di tipo "Intero", spostiamo il puntatore interno all'area di memoria
' pari al numero di byte di memoria occupata dal tipo "Intero":
    p = p + SizeOf(gb.Integer)
  Next
   
End


Conoscere con il Puntatore i valori di un vettore del tipo di un Oggetto

Dereferenziando il Puntatore ai dati di un vettore di Oggetti attraverso la sua proprietà .Data, vedremo che ogni 8 byte (a partire ovviamente da quello di indice 0, ossia il primo byte) sono conservati gli indirizzi di memoria ove sono contenuti gli Oggetti in ciascun elemento del vettore predetto. Un elemento di un vettore di Oggetti è sostanzialmente un Puntatore ad un indirizzo di memoria dell'Oggetto contenuto dal vettore.

Sarà dunque necessario dereferenziare ognuno di quegli indirizzi di memoria per ottenere i valori contenuti dagli Oggetti. Tali valori sono individuabili a cominciare dal 25° byte (indice 24).


Mostriamo un esempio con un vettore di tipo Struttura[ ]:

Public Struct STRUTTURA
  b As Byte
  sh As Short
  i As Integer
  s As String
End Struct


Public Sub Main()

 Dim sstt As New STRUTTURA[]
 Dim sr As STRUTTURA
 Dim p, p1, p2, p3, ps As Pointer
 Dim st As Stream
 Dim j, b As Byte
  
  With sr = New STRUTTURA
    .b = 1
    .sh = 11
    .i = 111
    .s = "sr num.1"
  End With
 
  sstt.Push(sr)
 
  With sr = New STRUTTURA
    .b = 2
    .sh = 22
    .i = 222
    .s = "sr num.2"
  End With
  
  sstt.Push(sr)

  With sr = New STRUTTURA
    .b = 3
    .sh = 33
    .i = 333
    .s = "sr num.3"
  End With
  
  sstt.Push(sr)

  p = sstt.data
 
' Dereferenziamo il puntatore al vettore di tipo STRUTTURA[]:
  st = Memory p For Read
' Andiamo a leggerne i dati byte per byte. Noteremo che ci sono tre valori che si riferiscono
' agli indirizzi di memoria delle tre variabili di tipo "STRUTTURA" contenuti dal vettore di tipo "STRUTTURA[]".
' Essendo tre puntatori, leggeremo In totale 3 * 8 byte: ossia 3 variabili per la quantità di byte di memoria occupata da un "Puntatore":
  For j = 0 To (sstt.Count * SizeOf(gb.Pointer)) - 1
    Read #st, b
    Print j;; Hex(b, 2)
  Next
  st.Close
  Print "============="
  
  
' Per poter ricavare i valori contenuti nella prima varibile di tipo "STRUTTURA", bisognerà ottenere il primo indirizzo di memoria,
' che è posto al primo byte (indice 0) dell'area di memoria occupata dal vettore di tipo "STRUTTURA[]":
' Utilizziamo la funzione di dereferenziazione di un "Puntatore di Puntatore":
  p1 = Pointer@(p)
  Print p1
  
' Per ottenere i valori contenuti dalla prima varibile di tipo "STRUTTURA", bisognerà dereferenziare il "Puntatore"
' a tale prima variabile spostandoci al 25° byte nell'area di memoria del "Puntatore":
  p1 = p1 + 24
  Print Byte@(p1)
' Tenendo conto in questo caso del necessario allineamento dei membri della varibile di tipo "STRUTTURA",
' ci spostiamo di 2 byte in avanti per leggere il membro di tipo "Corto" (quindi al 27° byte):
  p1 = p1 + 2
  Print Short@(p1)
' Dato che lo "Short" occupa 2 byte di memoria, ci spostiamo di altri 2 byte in avanti, e dereferziamo il dato per leggere il valore contenuto dal terzo membro:
  p1 = p1 + 2
  Print Int@(p1)
' Poiché l'Intero occupa 4 byte di memoria, ci spostiamo pdi 4 byte in avanti per leggere il dato della "Stringa".
' Poiché una variabile di tipo "Stringa" è sostanzialmente un "Puntatore", dovremo prima dereferenziare quel Puntatore al Puntatore
' della Stringa, e successivamente il Puntatore alla Stringa:
  p1 = p1 + 4
  ps = Pointer@(p1)
  Print String@(ps)
' oppure più brevemente:
  Print String@(Pointer@(p1))
  Print "======================="
   
   
' Per poter ricavare i valori contenuti nella seconda varibile di tipo "STRUTTURA", bisognerà ottenere il secondo indirizzo di memoria,
' che è posto al 9° byte (indice 8) dell'area di memoria occupata dal vettore di tipo "STRUTTURA[]". Infatti un "Puntatore" occupa 8 byte di memoria.
  p = p + 8
  p2 = Pointer@(p)
  Print p2   
' Per ottenere i valori contenuti dalla prima varibile di tipo "STRUTTURA", bisognerà dereferenziare il "Puntatore"
' a tale prima variabile spostandoci al 25° byte nell'area di memoria del "Puntatore":
  p2 = p2 + 24
  Print Byte@(p2)
' Tenendo conto in questo caso del necessario allineamento dei membri della varibile di tipo "STRUTTURA",
' ci spostiamo di 2 byte in avanti per leggere il membro di tipo "Corto" (quindi al 27° byte):
  p2 = p2 + 2
  Print Short@(p2)
' Dato che lo "Short" occupa 2 byte di memoria, ci spostiamo di altri 2 byte in avanti, e dereferziamo il dato per leggere il valore contenuto dal terzo membro:
  p2 = p2 + 2
  Print Int@(p2)
' Poiché l'Intero occupa 4 byte di memoria, ci spostiamo pdi 4 byte in avanti per leggere il dato della "Stringa".
' Poiché una variabile di tipo "Stringa" è sostanzialmente un "Puntatore", dovremo prima dereferenziare quel Puntatore al Puntatore
' della Stringa, e successivamente il Puntatore alla Stringa:
  p2 = p2 + 4
  ps = Pointer@(p2)
  Print String@(ps)
' oppure più brevemente:
  Print String@(Pointer@(p2))
  Print "======================="
   
   
' Per poter ricavare i valori contenuti nella terza varibile di tipo "STRUTTURA", bisognerà ottenere il terzo indirizzo di memoria,
' che è posto al 17° byte (indice 16) dell'area di memoria occupata dal vettore di tipo "STRUTTURA[]". Infatti un "Puntatore" occupa 8 byte di memoria.
  p = p + 8
  p3 = Pointer@(p)
  Print p3
' Per ottenere i valori contenuti dalla prima varibile di tipo "STRUTTURA", bisognerà dereferenziare il "Puntatore"
' a tale prima variabile spostandoci al 25° byte nell'area di memoria del "Puntatore":
  p3 = p3 + 24
  Print Byte@(p3)
' Tenendo conto in questo caso del necessario allineamento dei membri della varibile di tipo "STRUTTURA",
' ci spostiamo di 2 byte in avanti per leggere il membro di tipo "Corto" (quindi al 27° byte):
  p3 = p3 + 2
  Print Short@(p3)
' Dato che lo "Short" occupa 2 byte di memoria, ci spostiamo di altri 2 byte in avanti, e dereferziamo il dato per leggere il valore contenuto dal terzo membro:
  p3 = p3 + 2
  Print Int@(p3)
' Poiché l'Intero occupa 4 byte di memoria, ci spostiamo pdi 4 byte in avanti per leggere il dato della "Stringa".
' Poiché una variabile di tipo "Stringa" è sostanzialmente un "Puntatore", dovremo prima dereferenziare quel Puntatore al Puntatore
' della Stringa, e successivamente il Puntatore alla Stringa:
  p3 = p3 + 4
  ps = Pointer@(p3)
  Print String@(ps)
' oppure più brevemente:
  Print String@(Pointer@(p3))


' A scopo didattico mostriamo il tipo di variabile assunto dalla originaria variabile "ob":
  Print Object.Type(ob)

End