Pointer Tutorial
Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials
DivineDominionBetreff: Pointer Tutorial |
Do, Dez 23, 2004 19:05 Antworten mit Zitat |
|
---|---|---|
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 Leider Gottes alles in einer bmx-Datei und nicht als HTML Tutorial vorhanden, aber ich denke, dass das schon irgendwie geht 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
MasterKBetreff: Re: BMAX :: Pointer Tutorial |
Fr, Dez 24, 2004 2:58 Antworten mit Zitat |
|
---|---|---|
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 |
Fr, Dez 24, 2004 5:56 Antworten mit Zitat |
|
---|---|---|
Referenz = typensicherer gemanagter Objektverweis | ||
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen. |
Vertex |
So, Dez 26, 2004 12:17 Antworten mit Zitat |
|
---|---|---|
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 |
So, Dez 26, 2004 13:46 Antworten mit Zitat |
|
---|---|---|
vertex, eine referenz ist eine adresse (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 |
So, Dez 26, 2004 14:15 Antworten mit Zitat |
|
---|---|---|
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 |
Di, Dez 28, 2004 0:05 Antworten mit Zitat |
|
---|---|---|
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 | ||
christian.tietze@gmail.com - https://christiantietze.de
macOS |
Dreamora |
Di, Dez 28, 2004 0:28 Antworten mit Zitat |
|
---|---|---|
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 |
Di, Dez 28, 2004 1:07 Antworten mit Zitat |
|
---|---|---|
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? grüße |
||
DivineDominion |
Di, Dez 28, 2004 15:08 Antworten mit Zitat |
|
---|---|---|
Habs geändert. War mir nicht sicher. Aber wenn du meinst das der * davor gehört, bitte sehr | ||
christian.tietze@gmail.com - https://christiantietze.de
macOS |
David |
Di, Dez 28, 2004 18:49 Antworten mit Zitat |
|
---|---|---|
Hi!
Jau, so ists richtig!! Danke! grüße |
||
Black |
Di, Jan 04, 2005 23:14 Antworten mit Zitat |
|
---|---|---|
Wenn man eine Zeiger mit Print ausgibt, wird AFAIK die Addresse ausgegeben. | ||
bruZard |
Mi, Jan 05, 2005 8:46 Antworten mit Zitat |
|
---|---|---|
@Black: Es wird die Adresse ausgegeben auf welche der Pointer zeigt | ||
PIV 2,4GHz - 1GB DDR 333 - ATI Radeon9600 - WinXP - DX9.0c - BMax 1.14 - B3D 1.91 - 1280x1024x32
User posted image |
Vertex |
Mi, Jan 05, 2005 18:44 Antworten mit Zitat |
|
---|---|---|
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 |
Mi, Jan 05, 2005 19:25 Antworten mit Zitat |
|
---|---|---|
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 |
Mi, Jan 05, 2005 19:44 Antworten mit Zitat |
|
---|---|---|
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 |
Mi, Jan 05, 2005 21:10 Antworten mit Zitat |
|
---|---|---|
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 |
Mi, Jan 05, 2005 22:20 Antworten mit Zitat |
|
---|---|---|
Nöö, das passt scho. Es heißt ja 32 Bit Adressierung und nicht 31 Bit Adressierung Das erste Bit ist nur das Vorzeichenbit bei Integer. | ||
vertex.dreamfall.at | GitHub |
Nemesis |
Mi, Jan 05, 2005 22:39 Antworten mit Zitat |
|
---|---|---|
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 |
Mo, März 21, 2005 11:56 Antworten mit Zitat |
|
---|---|---|
Weiß jetzt nciht, ob das bei der 1.01 schon ging, wollte es aber mal zur vollständigkeit mit herreinschreiben:
BlitzBasic: [AUSKLAPPEN]
|
||
between angels and insects |
Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials
Powered by phpBB © 2001 - 2006, phpBB Group