Pointer Tutorial

Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen

DivineDominion

Betreff: Pointer Tutorial

BeitragDo, Dez 23, 2004 19:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Wollte mir durch Kommentare die Funktion von Pointern deutlich machen bzw. den Äquivalenten, die ich in C++ kennenlernte, einen neuen Namen zu geben (int *p; entspricht p:Int Ptr, *p = 1; entspricht Var p = 1 etc.).

Ich weiß nicht, ob das wirklich was zum Einstieg ist, aber durch einiges Feedback habe ich rausgefunden, dass meine Kommentare, die dann länger und länger und Später ein Text und dann ein Tutorial wurden, dass ich die ganz anschaulich und nett geschrieben hätte. Solange man nicht an meinen Ausdrücken und der Textgewalt knobelt sondern an den Pointern, bin ich zufrieden Smile

Leider Gottes alles in einer bmx-Datei und nicht als HTML Tutorial vorhanden, aber ich denke, dass das schon irgendwie geht Smile

Viel Spaß und schmeisst mir Feedback ruhig rüber, Anregungen oder Verbesserungen brauch ich immer.


Code: [AUSKLAPPEN]
Print "- - - - - - - - - - - - - - - - - - - -"

Rem
   Neu in BlitzMax ist OO - ObjektOrientierte Befehle.
   Dazu gehören auch die sogenannten Pointer, die nicht für jeden
   etwas triviales sind, was man durch angucken versteht und auch
   anwenden kann, sondern ein wenig mehr Geduld erfordern. Auch für
   mich, ich hab es erst beim Schreiben von Kommentaren langsam
   begriffen und die Kommentare in Texte umgewandelt - und voilá,
   da ist das Tutorial also.
   
   Nun gut. "Pointer" bedeutet in unserer lieben Muttersprache
   "Zeiger", worunter ich mir einen ausgestreckten Finger vorstelle,
   der auf etwas ZEIGT.
   
   So in etwa funktionieren die in objektorientierten Sprachen auch.
   Nur sind es keine Finger und es sind keine Dinge auf die gezeigt
   wird. Man spricht hier von Adressen (eine "Ortsbestimmung"), auf
   die ein Pointer zeigt, der durch eine Umwandlung auch den Wert
   der Adresse zurückliefert - Wert ist das, was wir Variablen mit
   einem einfachen "=" zuweisen, das ist glaube ich klar :)
   
   Und damit beginnt es.

EndRem


Rem
   Wir fangen an und geben einer Variable einen Wert. Das macht
   man ja täglich.
EndRem

Local i:Int = 10   'Integer, das sind Ganzzahlen :)

Rem   
   
   Jetzt machen wir uns mal Gedanken darüber, was das bedeutet!
   
   Irgendwo im Speicher steht nun ein Wert, '10'. Die Adresse ist
   dann  genau das, was es auch im Leben auf der Straße ist: ein
   Anhaltspunkt, um jemanden zu finden. Eine Hausnummer quasi.
   'i' wäre dann das Haus mit dem Inhalt, also dem smarten
   Informatiker, der dort wohnt: die '10'.
   Diese Adresse bezeichnet die Stelle, an der der Wert sitzt, sagt
   also wo das Haus steht. Was Adressen nun mal so tun.
   Als Array ließe es sich so darstellen:
      
      deinSpeicher[Adresse_von_irgendwas] = ...    'Irgendein Buchstabe hiervon z.B.
      deinSpeicher[Adresse_von_i] = 10          '<------ unser i!
      deinSpeicher[Adresse_von_was_anderem] = ...   'Meine PIN fürs Onlinebanking, die
                                 'nie aus dem Speichergelöscht wurde...
   
   Variablen sind dann, ja, ich kenne garkeinen Begriff dafür...
   Variablen, wie i, besitzen dann den Wert, der an der passenden
   Adresse steht. Sie sind quasi Pointer, nur komfortabel nutzbar.
   Pointer und Adressen sind nämlich sozusagen die zwei Teilstücke,
   die eine Variable ausmacht.
   Um Pointer im Endeffekt aber wie Variablen nutzen zu können, müssen
   wir vorher sagen, dass der Wert an der Adresse, auf die sie zeigen,
   ausgegeben werden soll. Sonst würden wir die Adresse selber ausgeben,
   die ein Pointer für gewöhnlich enthält.
   
   Pointer zeigen also auf Adressen, was man auch referenzieren nennt.
   Pointer selber haben als Inhalt nur die Adresse und müssen mit einer
   Umwandlung ausgegeben werden, damit man den Wert an der Adresse
   bekommt und nicht die Adresse selber. Dazu später mehr.
   
   Jetzt erstellen wir uns erst mal einen passenden Pointer.   
      
EndRem

Local p:Int Ptr    'Ptr steht für "PoinTeR", das Int gibt an,
            'dass wir einen Pointer auf eine Integer-Variable
            'erstellen wollen. Keine Kommas und Buchstaben also.

Rem
   
   Wir wissen jetzt, was Pointer akzeptieren: Adressen!
   Sie nehmen keine Buchstaben oder Zahlen an, sondern nur Adressen zu
   Orten, an denen Zahlen oder Buchstaben im Speichern sind; übertragen
   auf unser anschauliches Beispiel akzeptieren sie demnach nicht uns,
   den Menschen, der dort im Haus wohnt, sondern nur seine Anschrift.
   
   Wir müssen also irgendwie die Zahl, die in unserem 'i' steht, so
   ansprechen, dass wir deren Adresse finden, also nicht den Wert 10
   sondern sowas wie 'Adresse_von_i' von oben.
   Das geht sogar ganz leicht. Mit der Umwandlung durch 'Varptr'!
   
   Varptr (quasi "VARiable für PoinTeR umgewandelt") gibt dann
   nämlich den "Teil" einer Variable zurück, den Pointer akzeptieren:
   Adressen.
   Varptr stünde in unserem Straßenbeispiel oben für eine Visitenkarte,
   die wir jemandem geben, damit er unsere Adresse kennt und uns
   in der Stadt finden kann.
      
      Visitenkarte = Positionsinformation -> Adresse
   
   Dieser jemand ist der Pointer, der empfängt freudig unsere Adresse
   uns zeigt darauf. Er hat nicht den Wert an der Stelle (die Einwohner
   im Haus an der Adresse) sondern eben nur die Anschrift.
   
   Jetzt wenden wir das mal im Code an.
   
EndRem

p = Varptr i

rem
   
   Sensationell! Was ist nun geschehen?
   Wir haben die Adresse von 'i' rausgefunden ('Varptr i') und sie
   an unseren Pointer weitergegeben. Der akzeptiert auch nur
   Adressen, ist also mit der Adresse von 'i' sehr zufrieden, gibt
   keine Fehler aus und funktioniert so, wie ein Pointer funktionieren
   soll.
   Also erstmal gar nicht, denn der tut überhaupt nichts besonderes
   als eine Kopie der Adresse von 'i' zu sein.
   
   Wir haben unsere Visitenkarte jetzt mit Inhalt gefüttert. Sie ist aber
   eben nur eine Visitenkarte, eine Adresse, und, wie bereits erwähnt,
   nicht das Haus selber mit dem eigentlichen Inhalt.
   Das Haus ist nämlich 'i', und 'i' ist eine Variable und kein Pointer,
   keine Visitenkarte. Einleuchtend, nicht?
   
   Der Pointer ist also kein zweites Haus mit dem gleichen Inhalt
   sondern nur etwas, das die Position des Hauses kennt.
   Die Visitenkarte kann schließlich auch sagen, was im Haus ist, wenn
   man den Namen der Person haben will, der an der Adresse wohnt.
   
   Der Pointer ist in der Lage, uns diesen Namen zu liefern, besser gesagt
   die Person die dahinter steckt, weil wir ja 'i' einen Wert zugewiesen
   haben, den wir jetzt haben wollen.
   
   Das erledigt die Umwandlung durch 'Var' (merkbar durch "VARiable,
   auf die ... zeigt").

EndRem

Local k:Int = Var p    'k steht für "Kopie"; mir fiel nix anderes ein,
               'weil "VARiable, auf die p zeigt" uns den Wert
               'genauso zurückliefert wie ein einfaches 'k = i'

Print "Einwohner im Hause 'i': " + i
'Adressen lassen sich in BMax nicht anzeigen, da sie keinen Typ haben
'sondern nur sowas wie ausgestreckte Finger sind, die auf was zeigen :)
Print "Kopie der Einwohner durch 'k': " + k
Print "- - - - - - - - - - - - - - - - - - - -"


rem
   
   Jetzt zeige ich die Anwendung solcher "Umwege" mal an einem Beispiel.
   
   Man nutzt Pointer eigentlich nur, um Dinge zu referenzieren.
   Man übergibt Funktionen für gewöhnlich eine Variable, die man
   verändert und dann mit 'return' zurückgibt, damit die Änderung
   auch außerhalb der Funktion eine Wirkung zeigt:
      
      Function f( x )
         x = x + 1
         Return x
      EndFunction
      
      Print f( 1 ) '->  f( 1 ) = 1 + 1 = 2
      
   Ihr BlitzBasic-Benutzer da draußen nutzt fleißig glibale Variablen,
   woran man IM PRINZIP nicht sehr viel aussetzen kann, da es in BB
   nun mal gut klappte und schön einfach war.
   OO bietet einem nun aber auch eine andere Möglichkeit, um Variablen
   in einer Funktion zu modifizieren und die Änderungen ohne eine
   Globalität wirksam zu machen.
   
   Das sind nun mal die Pointer, die ich euch näherbringen will.
   Ihr übergebt einer Funktion diesmal nicht eine Zahl oder eine
   Variable (was darin resultiert, dass ihr Wert übergeben wird), sondern
   deren Adresse.
   Dann setzt ihr das Ziel eines Pointers auf diese Adresse und
   ändert den Pointer durch Umwandlung (Umwandlung, weil der Pointer
   nur Adressen akzeptiert und keine Zahlen, die man an der Adresse
   eigentlich haben will).

   Ich zeige das jetzt mal an einem Beispiel. Die Bedeutung der Begriffe
   "Pointer", "Adresse" und "Wert" solltet ihr jetzt eigentlich kennen,
   wie man auf die einzelnen Teile zugreift bzw. wie man Pointer deklariert
   auch.
   Ich kommentiere daher nur die Funktion der Anweisungen, und zwar
   kurz und knapp :)

EndRem

'Die Variable 'x' erstellen und mit einem Wert füllen
Local x:Int = 10

Print "Wert vom Integer x: " + x

'Die Funktion 'f()' deklarieren:
'Der Parameter 'y' ist ein Pointer.
Function f( y:Int Ptr )
   
   ''Var' funktioniert in beide Richtungen:
   'Einerseits kann man den Wert an des Pointers Adresse ausgeben,
   'andererseits kann man den Wert dort auch ändern!
   Var y = 20
   
EndFunction

'Die Adresse von 'x' durch 'Varptr' übergeben
f( Varptr x )

Print "Neuer Wert vom Integer x: " + x

rem
   
   Was neu war, war eben die Tatsache, dass man 'Var' in beide
   richtungen nutzen kann. Ja, wie durch zauberhand ändert sich 'x'
   nach Funktionsaufruf, obwohl wir eigentlich nur mit 'y' arbeiteten.
   
   Das Prinzip dahinter ist eben, dass man Sachen referenziert (Adresse
   an Pointer übergibt und mit dieser "Referenz" arbeitet) und nicht am
   Ende auf das Problem stößt, dass man in EINER Funktion ZWEI Werte
   zurückgeben will, was man bisher lösen musste, indem man beide
   Variablen die geändert werden sollten "global" machte.
   
   Das ganze lässt sich nun auch mit den in BMax ebenfalls neuen
   Objekten machen. Man benutzt dann keine Integer sondern eben eigene
   Types.

EndRem

Print "- - - - - - - - - - - - - - - - - - - -"


Rem
   A propos referenzieren: Man kann Variablen auch anders übergeben und
   nachhaltig ändern.
   Und zwar indem man den Parameter nicht als "Integer Pointer" deklariert
   sondern indem man eine Referenz zu einer Variable einleitet.
   Referenz ist das selbe wie oben, nur das man nicht extra Pointer etc.
   nutzen muss und es einfach nur "Referenz" heißt und nicht "Integer Pointer"
   oder so.
   "Referenz" lässt sich schwer erklären, da es eben ein deutsches Wwort ist
   und kein englisches... Wir stellen hier eine Art Beziehung her, wenn wir
   Referenzen benutzen, eigentlich genauso wie oben. Nur sind Referenzen um
   einiges sicherer, da man nicht nach "irgendwo in den Speicher" zeigen kann.
   Man kann Referenzen auch einfach ':Object' zuweisen und dann Arrays, Strings,
   eigene Instanzen oder Handles übergeben, die man dann auch wieder
   identifizieren kann (siehe Doku). Das wäre dann aber relativ schlecht designt
   oder eine sehr komische Funktion, wenn man verschiedene Objekte
   übergeben können soll.
   Wenn ich rechnen will, was nützt mir dann ein Duden anstelle eines
   Taschenrechners - designt eure Programme also anständig und nutzt nicht
   überall Referenzen um zu zeigen, dass ihr sie beherrscht, obwohl es
   ebensogut ohne ginge.
      
EndRem


'Die Funktion bekommt nun einen Parameter, der eine Referenz enthält.
'Referenzen durch 'Var' waren bisher immer dazu da, um Pointern den Wert
'zu entlocken oder zuzuweisen, nun sind sie ganz allgemein einfach
'nur Referenzen, "egal zu was" :)
Function byRef( y:Int Var )
   
   Rem
      Der Referenzierten Variable weisen wir einen Wert zu.
      Direkt.
      Ohne Umschweifungen.
      
      Da Referenz im Prinzip auch "Beziehung zu..." bedeutet,
      wird mittels dieser Beziehung der "Partner" verändert.
      
      Wir tun genau das selbe wie oben mit Pointern nur um
      eiiges kürzer.
   EndRem
   
   y = 30

End Function

'x ist jetzt noch immer 20, von weiter oben-
byRef( x )
'Nun nicht mehr, wie man sehen wird.


Print "Durch Beziehung geändertes 'x': " + x


Rem
   Kontrolliert jetzt mal euer "Output" Fenster in BMax, um
   die Ausgabe von Print zu lesen!
EndRem

Print "- - - ENDE :)"
Print " Grüße,"
Print "   DivineDominion, Weihnachten 2004"
christian.tietze@gmail.com - https://christiantietze.de
macOS
  • Zuletzt bearbeitet von DivineDominion am Di, Dez 28, 2004 15:08, insgesamt 2-mal bearbeitet
 

MasterK

Betreff: Re: BMAX :: Pointer Tutorial

BeitragFr, Dez 24, 2004 2:58
Antworten mit Zitat
Benutzer-Profile anzeigen
DivineDominion hat Folgendes geschrieben:

Code: [AUSKLAPPEN]
Wenn ich rechnen will, was nützt mir dann ein Duden anstelle eines Taschenrechners - designt eure Programme also anständig und nutzt nicht überall Referenzen um zu zeigen, dass ihr sie beherrscht, obwohl es ebensogut ohne ginge.

da muss ich widersprechen. referenzen sind in der normalen anwendungsentwicklung den pointern eindeutig vorzuziehen.
nun weiss ich natürlich nicht wie genau pointer und referenzen in bmax realisiert sind, aber ich nehme mal einfach an das ist ähnlich wie in c++.

eigentlich SOLLTE eine referenz von einem typ sein. genau wie ein pointer. referenzen sind aber deutlich sicherer als pointer, mit pointern kann man eine menge schindluder treiben. zB einfach auf beliebige speicheradressen zeigen lassen. für OS-entwicklung oder bei hardwarenaher programmierung macht das durchaus sinn (bzw ist unumgänglich), bei der anwendungsentwicklung aber sind pointer oftmals fehlerquelle 1.
referenzen ermöglichen saubereres und sichereres programmieren.
genau genommen sind sie natürlich nur hübsch verpackte pointer, eben entschärft. aber nicht ohne grund haben sprachen wie java oder .NET, also sprachen düe für die anwendungsentwicklung gedacht sind, keine echten pointer mehr (eben nur referenzen).
wenn die hardcore-hacker meinen mit pointern etwas "elegant" zu lösen dann ist es meistens nur eine knifflige lösung die ausser ihnen kein anderer verstehen kann. die zeit der byteschupser ist aber vorbei (also in der anwendungsentwicklung).
+++ www.masterk.de.vu +++
Lila FTW!
 

Dreamora

BeitragFr, Dez 24, 2004 5:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Referenz = typensicherer gemanagter Objektverweis
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen.

Vertex

BeitragSo, Dez 26, 2004 12:17
Antworten mit Zitat
Benutzer-Profile anzeigen
Super Tut Divi! Weisst du, wie man die Adresse eines Pointers sich ausgeben lassen kann?

MasterK: Was dauert länger zu kopieren? Den kompletten Inhalt eines Objekts oder nur die 32 Bit Adresse?

mfg olli
vertex.dreamfall.at | GitHub
 

MasterK

BeitragSo, Dez 26, 2004 13:46
Antworten mit Zitat
Benutzer-Profile anzeigen
vertex, eine referenz ist eine adresse Wink (müssen ja keine 32bit sein, können auch 64 sein). wie gesagt, referenzen sind praktisch entschärfte pointer.

objekte werden eigentlich nie komplett kopiert. gibt zwar ein paar sprachen oder bibliotheken in einigen sprachen die das ermöglichen, aber das nutzt man sicher nicht für einen funktionsaufruf.
+++ www.masterk.de.vu +++
Lila FTW!

Vertex

BeitragSo, Dez 26, 2004 14:15
Antworten mit Zitat
Benutzer-Profile anzeigen
OK nehme ich wieder alles zurück, hast Recht gehabt, ich dachte bei Referenzen werden die kompletten Objekte kopiert. Ja mit Referenzen kann man dann wirklich nix falsch machen.
vertex.dreamfall.at | GitHub

DivineDominion

BeitragDi, Dez 28, 2004 0:05
Antworten mit Zitat
Benutzer-Profile anzeigen
ToString() ist leider Gottes den objekten vorbehalten - damit könnte man laut Referenz nämlich die Adresse ausgeben. Pointer sind aber keine Objekte, drum geht das nicht Neutral
christian.tietze@gmail.com - https://christiantietze.de
macOS
 

Dreamora

BeitragDi, Dez 28, 2004 0:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Was stellt der Pointer selbst dar?

also wenn zb

i:Int

print varptr i

macht?
Müsste doch die Adresse sein, zumindest wenn man sie an importierte C / C++ funktionen übergibt wo der Ptr gefragt ist
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen.
 

David

BeitragDi, Dez 28, 2004 1:07
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi!

Code: [AUSKLAPPEN]

int p* => p:int ptr


Ist das so? Entspricht p:int ptr nicht eher "int *p"?
Oder soll das links kein C++ sein? Question

grüße

DivineDominion

BeitragDi, Dez 28, 2004 15:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Habs geändert. War mir nicht sicher. Aber wenn du meinst das der * davor gehört, bitte sehr Smile
christian.tietze@gmail.com - https://christiantietze.de
macOS
 

David

BeitragDi, Dez 28, 2004 18:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi!

Jau, so ists richtig!! Danke! Wink

grüße
 

Black

BeitragDi, Jan 04, 2005 23:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn man eine Zeiger mit Print ausgibt, wird AFAIK die Addresse ausgegeben.

bruZard

BeitragMi, Jan 05, 2005 8:46
Antworten mit Zitat
Benutzer-Profile anzeigen
@Black: Es wird die Adresse ausgegeben auf welche der Pointer zeigt Wink
PIV 2,4GHz - 1GB DDR 333 - ATI Radeon9600 - WinXP - DX9.0c - BMax 1.14 - B3D 1.91 - 1280x1024x32

User posted image

Vertex

BeitragMi, Jan 05, 2005 18:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Geht nicht!

Code: [AUSKLAPPEN]
Local iTest:Int
Local pTest:Int Ptr

iTest = 10
pTest = Varptr iTest

Print pTest


Hat sicher sein Sinn, das man nicht die Adresse von Pointern auslesen kann, damit man nicht das System vorkorksen kann. Einen pointer auf einem Pointer zeigen, und diesen diferenzieren geht übrigens auch nicht.

mfg olli
vertex.dreamfall.at | GitHub
 

Black

BeitragMi, Jan 05, 2005 19:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Uh, also es gibt zumindest eine Deklaration:
Local addr: Byte Ptr Ptr

Und die ist in einem der Modules (in der OpenStream-Funktion).
Und dort wird der Pointer auch dereferenziert.

Vertex

BeitragMi, Jan 05, 2005 19:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Geht dennoch nicht, der Pointer auf den Pointer ist ja diferenziert ja wieder ein Pointer, der sich dann nicht in Int oder String umwandeln kann:
Code: [AUSKLAPPEN]
Local iTest:Int
Local piTest:Int Ptr
Local ppTest:Int Ptr Ptr

iTest = 10
piTest = Varptr iTest
ppTest = Varptr piTest

Print Var ppTest
vertex.dreamfall.at | GitHub
 

Nemesis

BeitragMi, Jan 05, 2005 21:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Scheint in bb wirklich nicht zu gehen.

Hab mal folgendes probiert:


Test.bmx:
Code: [AUSKLAPPEN]

Import "test.c"

Extern
   Function bb_get_ptr_adr ( iptr:Int Ptr)
End Extern

Local iTest:Int = 10

Print bb_get_ptr_adr ( Varptr iTest )


test.c:
Code: [AUSKLAPPEN]

int bb_get_ptr_adr(int *ptr)
{
   return ptr;
}


Dachte eigentlich das müsste gehen, aber ich bekomme hier immer Negative adressen zurück.
Also ich denke eine Adresse kann nicht negativ sein oder?

Vertex

BeitragMi, Jan 05, 2005 22:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Nöö, das passt scho. Es heißt ja 32 Bit Adressierung und nicht 31 Bit Adressierung Smile Das erste Bit ist nur das Vorzeichenbit bei Integer.
vertex.dreamfall.at | GitHub
 

Nemesis

BeitragMi, Jan 05, 2005 22:39
Antworten mit Zitat
Benutzer-Profile anzeigen
achso klar.

im modul brl.blitz sind ein paar c functionen die bbstrings erzeugen können, dann könnte man das auch als string zurück geben, evtl. beim prototyp im Extern block Byte Ptr nehmen für en paramerter, dann müsste es für alle BB Typen Functionieren

Jan_

Ehemaliger Admin

BeitragMo, März 21, 2005 11:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Weiß jetzt nciht, ob das bei der 1.01 schon ging, wollte es aber mal zur vollständigkeit mit herreinschreiben:

BlitzBasic: [AUSKLAPPEN]

Local iTest:Int
Local piTest:Int Ptr

iTest = 10
piTest = Varptr iTest

Print Int(piTest)'zum Anzeigen muss der Pointer in ein Anzeigbares format gebracht werden
between angels and insects

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group