n° 185
Maggio/Giugno 2013
Maggio 22, 2013, 10:49:00 pm *
Benvenuto! Accedi o registrati.
Hai dimenticato l'e-mail di attivazione?

Accesso con nome utente, password e durata della sessione
Notizia:
 
   Indice   Linux Windows Techassistance Gameassistance videogame hardware Aiuto Ricerca Agenda Downloads Accedi Registrati  

* Messaggi recenti
Messaggi recenti
Pagine: [1]   Vai giù
  Stampa  
Autore Discussione: [VB6]Malloc/Puntatori/Liste  (Letto 1793 volte)
0 utenti e 1 Utente non registrato stanno visualizzando questa discussione.
VBeXtreme
Sr. Member
****

Karma: +17/-99
Scollegato Scollegato

Messaggi: 662



Mostra profilo
« inserita:: Febbraio 18, 2010, 05:36:37 pm »

Introduzione
L'altro giorno mentre parlavo con un utente mi è venuto in mente che in visual basic è

possibile usare malloc,puntatori e liste.
La carne sul fuoco è tantissima perciò procederemo con calma,il seguente Tips è per utenti esperti,la spiegazione di tutto l'articolo potrebbe richiedere anche 30 pagine,quindi ho cercato di semplificare tutto e tutto quello che non sono riuscito a spiegare chiedete che tanto io sono sempre qua.

Malloc
Per chi non sapesse cosa serve la funzione malloc ora la spiego:
Malloc è una "funzione del c" che serve a allocare della memoria dinamicamente.
Ovvero quando noi scriviamo:

Private/public/static/dim

Allochiamo della memoria che "statica" nello stack,ovvero il compilatore saprà dall'inizio quanta memoria e dove la usiamo integrandola nel file exe.
Quando invece usiamo memoria dinamica tipo:

Dim Dinamico() as long

il compilatore creerà una variabile dinamica nella memoria di heap.
Pultroppo vb6 non ci lascia libero uso della memoria dinamica,ma grazie alle api e a qualche stratagemma sarà tutto quasi molto semplice.
Iniziamo quindi con il codice che serve per la funzione della malloc:

Creiamo un nuovo progetto standard exe.
Creiamo un nuovo Modulo e lo chiamiamo mMalloc.
mMalloc:
Codice:
Option Explicit

''''''''''''
'''MALLOC'''
''''''''''''

Private Declare Function HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
Private Declare Function GetProcessHeap Lib "kernel32" () As Long

''''''''''''''''''''''''''''''''''''''''''
'''Malloc come linguaggio c            '''
'''Ritorna 0 se fallisce               '''
'''altrimenti l'indirizzo del puntatore'''
''''''''''''''''''''''''''''''''''''''''''

Public Function malloc(ByVal nBytes As Long) As Long
    Dim hHeap As Long: hHeap = GetProcessHeap()
    malloc = HeapAlloc(hHeap, 0, nBytes)
End Function

Public Sub Free(ByVal Ptr As Long)
    HeapFree GetProcessHeap(), 0, Ptr
End Sub

Le due funzioni sono molto semplici,la prima riserva lo spazio nella memoria che gli indichiamo.La seconda libera lo spazio di memoria allocata,questa è IMPORTANTE perchè LA MEMORIA NON VIENE LIBERATA AUTOMATICAMENTE.

Puntatori
I puntatori sono l'indirizzo della memoria che contiene la variabile.In visual basic per ottenere tale indirizzo si ricorre a:

varPtr()/strPtr()/objPtr()

Essi ci serviranno per poter accedere alla memoria allocata con malloc,infatti quando noi allochiamo memoria la funzione ci ritorna il puntatore di tale memoria,che noi dovremmo gestire per inserire il valore.

Vediamo il codice
Aggiungiamo quindi un modulo mPuntatori.
mPuntatori:
Codice:
Option Explicit

Public Const SIZEOF_BYTE As Long = 1
Public Const SIZEOF_INTEGER As Long = 2
Public Const SIZEOF_BOOLEAN As Long = 2
Public Const SIZEOF_LONG As Long = 4
Public Const SIZEOF_SINGLE As Long = 4
Public Const SIZEOF_DOUBLE As Long = 8
Public Const SIZEOF_CURRENCY As Long = 8
Public Const SIZEOF_OBJECT As Long = 4
Public Const SIZEOF_STRING As Long = 2
Public Const SIZEOF_VARIANT As Long = 16

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

''''''''''''''''''''''''''''''''''''''''''
'''Definizione Puntatori:              '''
'''Linguaggio c:  *Ptr=valore          '''
'''                Ptr=indirizzo       '''
'''Visual basic:  °L(Ptr) Usa puntatore'''
''''''''''''''''''''''''''''''''''''''''''

'BYTE
Property Get °B(ByVal Ptr As Long) As Byte
    CopyMemory °B, ByVal Ptr, SIZEOF_BYTE
End Property
Property Let °B(ByVal Ptr As Long, ByVal Value As Byte)
    CopyMemory ByVal Ptr, Value, SIZEOF_BYTE
End Property
'INTEGER
Property Get °I(ByVal Ptr As Long) As Integer
    CopyMemory °I, ByVal Ptr, SIZEOF_INTEGER
End Property
Property Let °I(ByVal Ptr As Long, ByVal Value As Integer)
    CopyMemory ByVal Ptr, Value, SIZEOF_INTEGER
End Property
'BOOLEAN
Property Get °E(ByVal Ptr As Long) As Boolean
    CopyMemory °E, ByVal Ptr, SIZEOF_BOOLEAN
End Property
Property Let °E(ByVal Ptr As Long, ByVal Value As Boolean)
    CopyMemory ByVal Ptr, Value, SIZEOF_BOOLEAN
End Property
'LONG
Property Get °L(ByVal Ptr As Long) As Long
    CopyMemory °L, ByVal Ptr, SIZEOF_LONG
End Property
Property Let °L(ByVal Ptr As Long, ByVal Value As Long)
    CopyMemory ByVal Ptr, Value, SIZEOF_LONG
End Property
'SINGLE
Property Get °N(ByVal Ptr As Long) As Single
    CopyMemory °N, ByVal Ptr, SIZEOF_SINGLE
End Property
Property Let °N(ByVal Ptr As Long, ByVal Value As Single)
    CopyMemory ByVal Ptr, Value, SIZEOF_SINGLE
End Property
'DOUBLE
Property Get °D(ByVal Ptr As Long) As Double
    CopyMemory °D, ByVal Ptr, SIZEOF_DOUBLE
End Property
Property Let °D(ByVal Ptr As Long, ByVal Value As Double)
    CopyMemory ByVal Ptr, Value, SIZEOF_DOUBLE
End Property
'CURRENCY
Property Get °C(ByVal Ptr As Long) As Currency
    CopyMemory °C, ByVal Ptr, SIZEOF_CURRENCY
End Property
Property Let °C(ByVal Ptr As Long, ByVal Value As Currency)
    CopyMemory ByVal Ptr, Value, SIZEOF_CURRENCY
End Property
'OBJECT ATTENZIONE MODO DIVERSO
Property Get °O(ByVal Ptr As Object) As Long
    °O = ObjPtr(Ptr)
End Property
Public Function °OO(ByVal Ptr As Long) As Object
    Dim o As Object
    CopyMemory o, Ptr, SIZEOF_OBJECT
        Set °OO = o
    CopyMemory o, 0&, SIZEOF_OBJECT
End Function

'STRING SPECIALE ATTENZIONE (COME IN ARRAY CHAR LINGUAGGIO C)!!!!!
Property Get °S(ByVal Ptr As Long, ByVal LenMallocByte As Long) As String
    Dim ptrChr() As Byte, lenptr As Long
   
    If LenMallocByte <> 0 Then
        lenptr = LenMallocByte * SIZEOF_STRING
        ReDim ptrChr(lenptr - 1) As Byte
        CopyMemory ptrChr(0), ByVal Ptr, lenptr
        °S = CtoVBstring(ptrChr())
    End If
End Property
Property Let °S(ByVal Ptr As Long, ByVal LenMallocByte As Long, ByVal Value As String)
    Dim ptrChr() As Byte, lenptr As Long
   
    If Len(Value) <> 0 Then
        lenptr = (Len(Value) + 1) * SIZEOF_STRING
        ptrChr() = Value
        ReDim Preserve ptrChr(lenptr - 1) As Byte
        ptrChr(UBound(ptrChr) - 1) = 0 '\0'
        CopyMemory ByVal Ptr, ptrChr(0), lenptr
    End If
End Property

'VARIANT
Property Get °(ByVal Ptr As Long) As Variant
    CopyMemory °, ByVal Ptr, SIZEOF_VARIANT
End Property
Property Let °(ByVal Ptr As Long, ByVal Value As Variant)
    CopyMemory ByVal Ptr, Value, SIZEOF_VARIANT
End Property


'FUNZIONI UTILI
Public Function CtoVBstring(arrChr() As Byte) As String
    Dim i As Long, ei As Long, ts() As Byte
   
    'Cerco il carattere \0
    ei = UBound(arrChr)
    For i = 0 To ei - 1 Step 2
        If arrChr(i) = 0 And arrChr(i + 1) = 0 Then
            If i > 0 Then
                'Preparo e copio l'array di caratteri
                ReDim ts(i - 1) As Byte
                CopyMemory ts(0), arrChr(0), i
                Exit For
            End If
        End If
    Next
   
    'se no c'e niente passo una stringa vuota(default)
    On Error Resume Next
        ei = UBound(ts)
    If Err.Number = 0 Then CtoVBstring = ts
   
End Function

'COPIA UDT
Public Sub §U(ByVal PtrDest As Long, ByVal PtrSrc As Long, ByVal LenByte As Long)
    CopyMemory ByVal PtrDest, ByVal PtrSrc, LenByte
End Sub


E qui il discorso si complica.
Dato che la gestione della memoria non è uguale per tutti ho creato una funzione per ogni gestione di essa,la lettera indica il tipo di memoria usata,in variant non ho messo nessuna lettera perchè io generalmente uso quel metodo.
Non preoccupatevi dopo illustrerò come si utilizza tutto.

Liste
una lista la si potrebbe definire come strutture che si puntano una dopo l'altra,conoscendo solo l'indirizzo della prima.

inseriamo un nuovo modulo mLista
mLista:
Codice:
Option Explicit


'Proprietà della lista
Public FirstElement As Long

Public Type type_Lista
    Value As Long
    Next As Long
End Type

'Esempio
Public Elemento As type_Lista

Public Sub AddElement(ByVal Value As Long)
    Dim N As type_Lista, B As Long, ptrN As Long
    Dim LS As Long
    Dim NewL As Long
   
    'creo l'elemento
    B = LenB(N)
    ptrN = VarPtr(N)
    NewL = malloc(B)
    If NewL <> 0 Then
        LS = LastElement
        If LS = 0 Then 'First
            FirstElement = NewL
            'prelevo l'udt
            §U ptrN, FirstElement, B
            N.Value = Value
            N.Next = 0
            'assegno il valore
            §U FirstElement, ptrN, B
        Else
            'prelevo l'udt
            §U ptrN, LS, B
            'assegno il valore next
            N.Next = NewL
            §U LS, ptrN, B
            'assegno il value al nuovo elemento
            §U ptrN, NewL, B
            N.Value = Value
            N.Next = 0
            'salvo il valore
            §U NewL, ptrN, B
        End If
    End If
End Sub

Public Function LastElement() As Long
    Dim N As type_Lista, B As Long, ptrN As Long
    Dim oldN As Long
   
    If FirstElement <> 0 Then
        B = LenB(N)
        ptrN = VarPtr(N)
        'prelevo il primo elemento
        §U ptrN, FirstElement, B
        oldN = FirstElement
        Do
            If N.Next = 0 Then LastElement = oldN: Exit Do
            oldN = N.Next
            §U ptrN, N.Next, B
        Loop
    End If
End Function

Public Sub FreeLista()
    Dim N As type_Lista, B As Long, ptrN As Long
   
    If FirstElement <> 0 Then
        B = LenB(N)
        ptrN = VarPtr(N)
        'prelevo il primo elemento
        §U ptrN, FirstElement, B
        'lo cancello
        Free FirstElement
        Do
            If N.Next = 0 Then Exit Do
            §U ptrN, N.Next, B
            Free N.Next
        Loop
    End If
End Sub

'Esempio di ricerca
Public Function FindElement(ByVal Value As Long) As Long
    Dim N As type_Lista, B As Long, ptrN As Long
    Dim oldN As Long
   
    If FirstElement <> 0 Then
        B = LenB(N)
        ptrN = VarPtr(N)
        'prelevo il primo elemento
        §U ptrN, FirstElement, B
        oldN = FirstElement
        Do
            If N.Value = Value Then FindElement = oldN: Exit Do
            If N.Next = 0 Then FindElement = -1: Exit Do
            oldN = N.Next
            §U ptrN, N.Next, B
        Loop
    End If
End Function

Test
Ora Vediamo come utilizzare tutto:
Prima di tutto creiamo un nuovo modulo di classe Class1:
Dentro metteremo solo una variabile

Pubblic Prova as string

Creiamo 5 command button di dimensioni egregie nel form1.
Form1:
Codice:
Option Explicit

Private Sub Command1_Click()
    Dim p As Long

    'ESEMPIO UTILIZZO PUNTATORI A TIPI SEMPLICI
    'Solo il primo è ben commentato,dato che i restanti servono per
    'capire le varie implementazioni con tipi di dati diversi.
   
    'BYTE
   
    'Alloco la memoria dinamicamente
    p = malloc(SIZEOF_BYTE)
   
    'Se riesco ad allocarla
    If p <> 0 Then
   
        'Inserisco il valore nel puntatore usando l'apposito comando
        °B(p) = 10
       
        'Visualizzo l'indirizzo e il valore del puntatore
        MsgBox "L'indirizzo di puntatore è: " & CStr(p) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°B(p)) _
               , vbOKOnly, "Prova"
       
        'Libero la memoria
        Free p
    End If
   
    'INTEGER
    p = malloc(SIZEOF_INTEGER)
    If p <> 0 Then
        °I(p) = 1000
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°I(p)) _
               , vbOKOnly, "Prova"

        Free p
    End If
   
    'BOOLEAN
    p = malloc(SIZEOF_BOOLEAN)
    If p <> 0 Then
        °E(p) = True
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°E(p)) _
               , vbOKOnly, "Prova"

        Free p
    End If
   
    'LONG
    p = malloc(SIZEOF_LONG)
    If p <> 0 Then
        °L(p) = 700000
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°L(p)) _
               , vbOKOnly, "Prova"

        Free p
    End If
   
    'SINGLE
    p = malloc(SIZEOF_SINGLE)
    If p <> 0 Then
        °N(p) = 1.1
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°N(p)) _
               , vbOKOnly, "Prova"

        Free p
    End If
   
    'DOUBLE
    p = malloc(SIZEOF_DOUBLE)
    If p <> 0 Then
        °D(p) = 1.2569458
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°D(p)) _
               , vbOKOnly, "Prova"

        Free p
    End If
   
    'CURRENCY
    p = malloc(SIZEOF_CURRENCY)
    If p <> 0 Then
        °C(p) = 10012.2556
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°C(p)) _
               , vbOKOnly, "Prova"

        Free p
    End If
   
End Sub

Private Sub Command2_Click()
    Dim p1 As Long
    Dim p2 As Long
    Dim p3 As Long
   
    'UTILIZZO CONSIGLIATO PER TUTTI I TIPI DI DATI + ESEMPIO MEMORY LEAK
    'solo per una piu facile gestione del codice.
   
    'il codice seguente presenta un ERRORE di memory leak
    'Se infatti una variabile viene allocata e le altre no
    'allora non sarà scaricata dalla memoria.
   
    'VARIANT
    p1 = malloc(SIZEOF_VARIANT)
    p2 = malloc(SIZEOF_VARIANT)
    p3 = malloc(SIZEOF_VARIANT)
   
    If (p1 <> 0) And (p2 <> 0) And (p3 <> 0) Then
       
        'Esempio normale
       
        °(p1) = 1
        °(p2) = 2
        °(p3) = °(p1) + °(p2)
       
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p3) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°(p3)) _
               , vbOKOnly, "Prova"
       
        'con casting x sicurezza di tipo
       
        °(p1) = CDbl(1)
        °(p2) = CDbl(2)
        °(p3) = °(p1) + °(p2) + 0.2 'qui non serve perchè tutti dbl
                                    'quindi p3 sara un casting
                                    'automatico a dbl:
                                    '°(p3) =cDbl(°(p1) + °(p2) + 0.2)
       
   
        MsgBox "L'indirizzo di puntatore è: " & CStr(p3) & vbCrLf & _
               "Il valore di Puntatore è:" & CStr(°(p3)) _
               , vbOKOnly, "Prova"
       
        Free p1
        Free p2
        Free p3
    End If
   
End Sub

Private Sub Command3_Click()
    Dim p As Long
    Dim o1 As Class1
    Dim o2 As Class1
    Dim v As String
   
    'Gli oggetti è meglio usarli in un modo diverso
   
    'Creo un oggetto
    Set o1 = New Class1
   
    'gli imposto le proprietà
    o1.prova = "Ciao mondo"
   
    'Prendo il puntatore
    p = °O(o1)  'p = ObjPtr(o1)
   
    'visualizzo il dato nel puntatore senza intellisense
    'usando esplicitamente il puntatore ad oggetto
    MsgBox °OO(p).prova
   
   
    'con intellisense copiando il puntatore
    'in un oggetto che poi distruggerò
    Set o2 = °OO(p)
        MsgBox o2.prova
    Set o2 = Nothing
   
    'distruggo l'oggetto
    Set o1 = Nothing
End Sub

Private Sub Command4_Click()
   Dim p As Long
   Dim LenString As Long
   
   'E PER LE STRINGHE
   'creo lo spazio necessario per la stringa
   LenString = 11 '11 caratteri importante che sia di un carattere piu grande
                  'proprio come nel linguaggio c
   p = malloc(LenString * SIZEOF_STRING)
   
   'memorizzo la stringa
   °S(p, LenString) = "Ciao Mondo"
   
   'visualizzo la stringa
   MsgBox °S(p, LenString)
   
   'libero la memoria
   Free p
   
   'ATTENZIONE SI POTREBBE ESSERE TENTATI A USARE IL VARIANT
   p = malloc(SIZEOF_VARIANT)
   °(p) = "Ciao Mondo"
   MsgBox °(p)
   Free p
   'MA DA COME SI NOTA NON FUNZIONA
End Sub

Private Sub Command5_Click()
    'USIAMO LA LISTA
    AddElement 1
    AddElement 2
    AddElement 3
    AddElement 4
    AddElement 5
   
    MsgBox "Il puntatore dell'elemento ricercato è:" & FindElement(4), vbOKOnly, "Ricerca"
   
    FreeLista
End Sub

Conclusioni
Ora cercate di analizzare tutto il codice e vedrete che qualcosa ci capite,per i meno esperti consiglio di studiare i puntatori in c e le liste,dopo tutto ciò si potrebbe creare anche una pila,questo ve lo lascio come esercizio tanto il codice lo conoscete gia Ghigno

Registrato

Ragionare non è nient’altro che calcolare
"Thomas Hobbes"
Pagine: [1]   Vai su
  Stampa  
 
Vai a:  

Copyright © 2011 Edizioni Master SpA. p.iva : 02105820787

Tutti i diritti di proprietà letteraria e artistica riservati. - Privacy



Links to Page