Zitat von
the_real_didi:
@Muetze1: Das einzige wo ich noch nicht so mit komme ist die Sache mit den Pointern. Zum einen warum ich die lokale Variable eigentlich so richtig brauche. Die ist nach dem Ende der Procedure weg und die Daten sind noch da. Die hängen am Knoten, das ist klar, aber was macht dann die Variable Datensatz?
Du hast nach meiner Deklaration 2 Typen: TDatensatz und PDatensatz. TDatensatz deklariert einen Typ der direkt diese beiden Variablen deines Records beinhaltet. Der Typ PDatensatz ist ein Typ, welcher nur einen Zeiger darstellt. Dabei definiert er auch gleich, wie der Speicher aussieht, auf den er zeigt: er sieht aus wie TDatensatz. Wenn du nun eine lokale Variable deklarierst, dann wird dort lokal speicher für diese reserviert, welcher nach verlassen der Procedure wieder anders gebraucht wird und daher nicht fest ist. Wenn du nun eine lokale Variable vom Typ TDatensatz lokal anlegst, dann würden die Zuweisungen auf ID und Typ lokal gespeichert werden und verloren gehen bei verlassen der Procedure, da der Speicher direkt reserviert wird im lokalen Bereich. Wenn du nun eine Variable vom Typ PDatensatz lokal deklarierst, dann wird dort nur der Speicherplatz für einen Zeiger vorgehalten. Dieser zeigt auf irgendeine Adresse im Speicher. Um die Variable nutzen zu können, muss der Zeiger auf einen gültigen und alloziierten Speicher zeigen, dieses geschieht durch New(). New() weiss durch den Typ, wieviel Speicher alloziieren muss (die Grösse von TDatensatz auf die die Variable ja zeigt). Die Adresse wo im Speicher er Platz bekommen hat, trägt New() in die PDatensatzvariable ein. Beim Verlassen der Procedure wird zwar der Speicherplatz des Zeigers wieder anders genutzt, aber der mit New() alloziierte Speicher nicht - dieser wird erst durch einen Aufruf von Dispose wieder freigegeben. Um dies später noch zu können und auch später noch auf die dort abgelegten Daten zugreifen zu können, müssen wir uns diesen Zeiger merken. Dies erledigen wir, in dem wir die Adresse der Daten (mehr ist ein Zeiger nicht - es ist nur eine Adresse, wo man was findet - eine reine Adressangabe im Speicher) in der Data Eigenschaft des Nodes zuweisen und der merkt sich die. Wohin er zeigt und wie gross der Bereich ist auf den er zeigt oder was für Daten dort liegen, ist der Data Eigenschaft nicht bekannt (untypisierter Zeiger (Pointer), er weiss nur, er merkt sich eine Adresse, aber nicht auf welchen Typ er zeigt, also welchen Aufbau die Daten dort haben).
Zitat von
the_real_didi:
Zum anderen hab ich die Bedeutung dieses ^-Zeichens noch nicht ganz verstanden. Und auf was sie sich bezieht. Du meintest ja, dass ich auf die Daten so zugreifen soll.
Und da kommen wir nun dazu: Das ^ dereferenziert. Also ein Pointer merkt sich eine Adresse - eine Stelle im Speicher. Du musst nun aber dem Compiler sagen, ob du nun bei Zuweisungen diese Adresse haben willst, die sich der Pointer merkt, oder ob du auf den Speicherbereich zugreifen willst, wohin er zeigt (also an die gemerkte Adresse selber). Das geschieht durch die Angabe von dem ^. Wenn du ein ^ hinten anhängst, dann greifst du an die Stelle zu, wohin der Zeiger zeigt und nicht auf die gemerkte Adresse selber. Und da ist nun die Sache mit den untypisierten Zeigern und den typisierten. PDatensatz ist ein typisierter Zeiger, da er gleich mit definiert wie die Datenstruktur aussieht (wie TDatensatz) an der Stelle wo er hinzeigt. Ein Pointer weiss dies nicht und daher
wird beim Zugriff der Typ Pointer auf den Pointer-Typ PDatensatz umgewandelt und schon weiss der Compiler auch wie die Daten dort aussehen und das es dort auch ID und Typ gibt.
- Node.Data = Adresseablage - merkt sich eine Adresse
- Node.Data^ = spricht die Daten an, die an der gemerkten Adresse liegen (dereferenzieren). Typ ist hier unbekannt (da Pointer)
- PDatensatz(Node.Data) = Adressablage - merkt sich die Adresse und weiss durch den Typ, wie die Daten an der Adresse organisiert sind
- PDatensatz(Node.Data)^ = das ist nun vom Typ TDatensatz, da er durch die Dereferenzierung (^) an die Stelle geht, welche an der in Node.Data abgelegten Adresse liegen. Durch den Typ wissen wir, dass dort TDatensatz liegt...
Zitat von
the_real_didi:
showmessage(TDatensatz(node.Data)^.ID);
Dann schau nochmal hin und kopier nochmal richtig. Ich hatte PDatensatz geschrieben, also den typisierten Zeiger genommen.
Zitat von
the_real_didi:
Da meckerte Delphi, dass es eine ungültige Typumwandlung sei. Deshalb habe ich einfach dieses Zeichen in die Klammern rein genommen, dann hat es funktioniert. Ich weiß aber nicht warum. Hab ich da noch irgendwo n Fehler in ner Deklaration?
Nein, aber mit dem ^ innerhalb der Klammer derefenzierst du ja (also sprichst die Daten an, die an der Stelle liegen, welche in Node.Data per Adresse beschrieben wird). Und dann sagst du dem Compiler, dass die Daten and er Speicherstelle wie TDatensatz aufgebaut ist.