Kazalci v VB.NET

Da tale forum ne bo tako sameval Wink [;)]

Saj veste kako je s kazalci v C ali C++: kazalcu prirediš lokacijo spremenljivke in potem z njim počneš kar hočeš. Preko njega lahko dostopaš do vrednosti spremenljivke ali pa mu prirediš lokacijo druge spremenljivke. Ali obstaja kaj takega v VB.NET?

Konkreten primer:

Recimo, da imam razred Node, ki mi predstavlja vozlišče v trojiškem drevesu (vsako vozlišče ima vrednost tipa String in največ 3 sinove):

Class Node

   Public left As Node   'polja bi seveda morala biti property-i... pa pustimo to

   Public middle As Node

   Public right As Node

      Public value As String

End Class

Seveda lahko kličem proceduro in podam node po referenci:

Sub KrNeki (ByRef myNode As Node)

Pri tem klicu se bo myNode res obnašal kot kazalec.

Kaj pa drug primer: recimo, da bi rada znotraj procedure preverila, kateri od sinov vozlišča vsebuje niz nekNiz in tistega od sinov zamenjala z drugim vozliščem:

Dim theNode as Node   'sin, ki vsebuje vrednost nekNiz

If myNode.left.value = nekNiz Then

   theNode = myNode.left

ElseIf myNode.middle.value = nekNiz Then

   theNode = myNode.middle

ElseIf myNode.right.value = nekNiz Then

   theNode = myNode.right

End If

theNode = GenerateRandomNode("new node value")

Skratka, če je veljalo myNode.middle.value = nekNiz, potem bi rada, da se to vozlišče zamenja z novim in velja myNode.middle.value = "new node value". Vendar se to ni zgodilo. Vozlišče theNode sicer ima novo vrednost, vendar ta ne vpliva na vozlišče myNode.middle, ki je ostalo takšno kot prej.

Če bi imela na voljo kazalce, bi v kazalec shranila referenco na myNode.middle in ne bi bilo nobenih problemov.

A sem kaj spregledala? Vem, da obstaja razred Pointer, ampak VB.NET ne dovoli uporabe njegovih metod.

Avtor: newdrim, objavljeno na portalu SloDug.si (Arhiv)

Leave a comment

Please note that we won't show your email to others, or use it for sending unwanted emails. We will only use it to render your Gravatar image and to validate you as a real person.

AndrejT
AndrejT - sreda, 22. marec 2006

Ja, LinkedList ti omogoča delo z množico nekih elementov recimo v tvojem primeru števil), ki so med seboj povezane (lahko v drevo) in se po njih lahko sprehajaš preko referenčnih povezav. Po drugem tvojem postu pa vidim, da te to ne zanima

newdrim
newdrim - sreda, 22. marec 2006

AndrejT: ne razumem, kako bi si pomagala z LinkedList... a zato, da bi v njem hranila sinove vozlišča ali kako?  

newdrim
newdrim - sreda, 22. marec 2006

ExAmigan, moje vprašanje se v resnici ne nanaša na vsebino problema (operacije nad drevesom), ampak na kazalce kot take. Problem z drevesom je dodan le kot ilustracija (očitno ne preveč dobra). Kot sem napisala v zadnjem postu, sem zadevo rešila točno tako kot si sam svetoval: klicala sem metodo, ki je sprejela parameter po referenci, namesto po vrednosti. Hec je v tem, da se mi zdijo kazalci bolj naravni za take operacije. Glede na to, da sem zbudila toliko zanimanja (hvala, fantje - makes me feel special ), vam bom pa še razkrila kako dejansko izgleda koda. Imam drevo, ki ima naslednjo (zelo neuporabno) lastnost: v vozliščih so naravna števila. Če je ostanek pri deljenju s 3 enak 0, spada število v levo poddrevo, če je enak 1 spada v srednje poddrevo in če je enak 2 spada v desno poddrevo. Če neposredno pod trenutnim vozliščem ni prostora (ker ima vozlišče že sina v danem poddrevesu), se spustim nivo nižje in spet delim s 3 (zato imam v spodnji kodi spremenljivki guide in remainder). Skratka, spodnja koda je rešitev problema in IMHO deluje b.p. Vprašanje je le, ali v VB.NET obstajajo kazalci (ker bi raje delala z njimi ko bom imela naslednjič podobno situacijo). Pa še to: seveda se da zadevo veliko bolj elegantno in brez kakršne koli potrebe po kazalcih rešiti rekurzivno. Tudi to sem že naredila . Zanimajo me samo kazalci (sem izbirčna, kaj?). Public Sub InsertIterative(ByRef rootNode As TreeNode, ByVal value As Integer)   Dim wasInserted As Boolean = False   Dim guide As Integer = value   Dim node As TreeNode = rootNode    'če je rootNode = Nothing, ustvarimo novo vozlišče   wasInserted = CreateNewNode(rootNode, value)    'sicer poiščemo ustrezno mesto za novo vozlišče   While Not wasInserted      Dim remainder As Integer = guide Mod 3      guide = guide \ 3      If guide = 0 Then guide = value       Select Case remainder         Case 0            wasInserted = CreateNewNode(node.Left, value)            node = node.Left         Case 1            wasInserted = CreateNewNode(node.Middle, value)            node = node.Middle         Case 2            wasInserted = CreateNewNode(node.Right, value)            node = node.Right      End Select   End While End Sub 'če je node = Nothing, popravimo referenco tako, da kaže na novo ustvarjeno vozlišče in'vrnemo true; sicer vrnemo false in ne naredimo ničesarPrivate Function CreateNewNode(ByRef node As TreeNode, ByVal value As Integer) As Boolean    If node Is Nothing Then      node = New TreeNode(value)      Return True   End If    Return FalseEnd Function

AndrejT
AndrejT - sreda, 22. marec 2006

Mogoče ni direktno povezano s tvojim vprašanjem, ampak tvoj problem bi bil znal biti rešljiv tudi z uporabo LinkedList(Of string), z nekaj "dodatne opreme". Če ne drugega, je vsaj za pogledat kot princip referenc in povezanih vozlišč...

ExAmigan
ExAmigan - sreda, 22. marec 2006

Nisem povsem prepričan, da razumem, kaj želiš izvesti v metodi PrerazporediSinove(Node), a če želiš da se sprememba parametra kot zamenjava objekta, na katerega ta kaže (torej kot zamenjava vrednosti kazalca), odrazi navzven, potem se moraš pač poslužiti prenosa po referenci. V primeru prenosa po vrednosti se bodo nasprotno odrazile le spremembe v objektu, ne pa tudi parametra samega.   VB.NET je v tem pogledu skladen z delovanjem Jave in C#, konceptualno pa se mi to tudi ne zdi toliko drugačno od kazalcev v C/C++, čeprav priznam, da sem v tem jeziku že malo zarjavel.   Ob ponovnem branju svojega odgovora upam, da sem dovolj jasen, sicer pa je najbolje, da podaš celoten primer, kaj želiš doseči.

newdrim
newdrim - torek, 21. marec 2006

Ah, saj sem vedela, da bi si morala izmisliti boljši primer. Pa reciva, da tega ne moreš narediti, ker so operacije, ki jih nameravaš izvesti nekako odvisne od lastnosti theNode. Recimo, da theNode = GenerateRandomNode("new node value") zamenjam z theNode = PrerazporediSinove(theNode) Če se pa se želim iterativno (torej brez rekurzije) sprehajati po takem drevesu glede na vrednosti v vozliščih in vmes vstavljati nova vozlišča, lahko postane kar zabavno V mojem primeru sem tiste stvari, ki sem jih hotela narediti z vozliščem, dala kar v svojo proceduro, ki sem ji podala vozlišče po referenci. Procedura je zato lahko spremenila karkoli, vključno z zamenjavo vozlišča, ampak bi si želela narediti zadevo s kazalci, če je to mogoče. IntPtr sicer predstavlja referenco na košček memorije, samo ne vem, kako bi mu priredila naslov kakšnega objekta.    

MihaM
MihaM - torek, 21. marec 2006

Živjo Andreja, V tvojem primeru je theNode samo reference na enega od otrok medtem ko myNode ohrani svoje reference. Kakorkoli, tako bo pa delalo: theNode = GenerateRandomNode("new node value") If myNode.left.value = nekNiz Then    myNode.left = theNode ElseIf myNode.middle.value = nekNiz Then    myNode.middle = theNode ElseIf myNode.right.value = nekNiz Then    myNode.right = theNode End If