Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Pointeradresse auslesen (https://www.delphipraxis.net/201931-pointeradresse-auslesen.html)

paul.kunig 11. Sep 2019 09:38

Delphi-Version: 5

Pointeradresse auslesen
 
Hallo zusammen,

folgender Code:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Eingabe: ^String;
begin
  New(Eingabe);
  Eingabe^ := Edit1.Text;

  ShowMessage(Eingabe^ + #13#10 +
  IntToStr(Integer(Eingabe)) + #13#10 +
  IntToStr(Integer(@Eingabe)) + #13#10 +
  IntToStr(Integer(Addr(Eingabe)))
  );

  Dispose(Eingabe);
end;
Führe ich das Ganze aus, erhalte ich folgende Werte:
1) Inhalt des Eingabefeldes
2) Einen Dezimalwert, der auch unter lokale Variablen in der Entwicklungsumgebung als Hexadezimalwert angezeigt wird.
3) Einen siebenstelligen Integer
4) Den selben Integer wie in Punkt 3.

Welcher von diesen Werten ist nun die Speicheradresse des Zeigers und woher kommt der verbliebene Wert?

Gruß
Paul

Amateurprofi 11. Sep 2019 10:44

AW: Pointeradresse auslesen
 
Siehe eingefügte Kommentare im Code
Delphi-Quellcode:
var
   Eingabe: ^String;
begin
   New(Eingabe);
   Eingabe^ := Edit1.Text;

   ShowMessage(Eingabe^ + #13#10 +          // Der Text aus dem Edit nach Eingabe kopierte Text
   IntToStr(Integer(Eingabe)) + #13#10 +    // Adresse des mit New allozierten Speicherbereichs
   IntToStr(Integer(@Eingabe)) + #13#10 +   // Adresse der Variablen "Eingabe"
   IntToStr(Integer(Addr(Eingabe)))        // dto
   );

   Dispose(Eingabe);
end;

paul.kunig 11. Sep 2019 11:00

AW: Pointeradresse auslesen
 
Hallo Amateurprofi,

danke für deine Antwort. Noch einmal zum Verständnis.

Die Variable "Eingabe" ist eine Typisierter Zeiger.
In diesen Speicherbereich wird der Wert aus dem Eingabefeld gespeichert.

Also sollte ich zwei Werte abrufen können.
1) Den Werte der unter dieser Speicheradresse abgelegt ist.
2) Die Adresse wo der Wert abgelegt ist.

Aus welchem Grund sollte die Variable "Eingabe", die ja ein Zeiger ist, erneut eine Speicheradresse bekommen?

Gruß
Paul

Amateurprofi 11. Sep 2019 11:24

AW: Pointeradresse auslesen
 
Zitat:

Zitat von paul.kunig (Beitrag 1445695)
Hallo Amateurprofi,
Also sollte ich zwei Werte abrufen können.
1) Den Werte der unter dieser Speicheradresse abgelegt ist.
2) Die Adresse wo der Wert abgelegt ist.
Aus welchem Grund sollte die Variable "Eingabe", die ja ein Zeiger ist, erneut eine Speicheradresse bekommen?

Gruß
Paul

Zu 1) und 2):
Kannst und machst Du doch
1) Den Werte der unter dieser Speicheradresse abgelegt ist.
Delphi-Quellcode:
Eingabe^
.
2) Die Adresse wo der Wert abgelegt ist.
Delphi-Quellcode:
Eingabe
.
3) Aus welchem Grund sollte die Variable "Eingabe", die ja ein Zeiger ist, erneut eine Speicheradresse bekommen?
Weil Du mit
Delphi-Quellcode:
New(Eingabe)
diesen Speicherbereich allozierst und die Adresse dieses Speicherbereichs in Eingabe stellst.

Das New und Dispose kannst Du auch weglassen, indem Du Eingabe als String deklarierst also:
Delphi-Quellcode:
var Eingabe:String;
und
Delphi-Quellcode:
Eingabe:=Edit1.Text;

paul.kunig 11. Sep 2019 12:54

AW: Pointeradresse auslesen
 
Ich möchte den Wert des Eingabefeldes im Heap speichern, daher der Typisierte Zeiger.

Um den Wert aus dem Speicherbereich auszulesen wird dieser dereferenziert, also Eingabe^.
Um die Speicheradresse auszulesen wird @ oder Addr() verwendet.

So weit, so gut.

Wenn ich den Zeiger nicht mit New() erzeuge, gibt es eine Zugriffsverletzung.
Also ist diese Speicherzuweisung notwendig.

Wozu sollte noch eine Adresse für ein und die selbe Variable, in diesem Fall ein Zeiger, benötigt werden.

Wobei diese anscheinend in verschiedenen Bereichen des Speichers abgelegt sind.
Adresse des Zeigers = achtstellig.
Adresse der Variable, die ja der Zeiger ist = siebenstellig.

Es erschließt sich mir nicht, warum die Adresse eines Zeigers in einer Variable gespeichert werden soll, obwohl der Zeiger selber die Möglichkeit bietet sich selber auszulesen.

Was übersehe ich?

Amateurprofi 11. Sep 2019 13:51

AW: Pointeradresse auslesen
 
Zunächst mal:
Wir sprechen über Delpi 5, wenn ich #1 richtig interpretiere, also String = ShortString.

Zitat:

Ich möchte den Wert des Eingabefeldes im Heap speichern, daher der Typisierte Zeiger.
.
Was aber aus #1 nicht hervorgeht.

Zitat:

Wenn ich den Zeiger nicht mit New() erzeuge, gibt es eine Zugriffsverletzung.
Also ist diese Speicherzuweisung notwendig.
.
Ja, wenn "Eingabe" als ^String deklariert ist, ist das so.

Zitat:

Wozu sollte noch eine Adresse für ein und die selbe Variable, in diesem Fall ein Zeiger, benötigt werden.
.
"Eingabe" ist die Variable, in der die Adresse des allozierten Speicherbereiches steht.
Der Inhalt von "Eingabe" ist diese Adresse.
Also: Die Variable "Eingabe" und die Adresse des allozierten Speicherbereiches sind nicht dasselbe.
Egal, ob du den Speicher mit New(Eingabe) oder z.B. mit GetMem(Eingabe, SizeOf(String)) allozierst, brauchst du einen Ort, wo die Adresse des allozierten Speichers gespeichert wird

Zitat:

Wobei diese anscheinend in verschiedenen Bereichen des Speichers abgelegt sind.
Adresse des Zeigers = achtstellig.
Adresse der Variable, die ja der Zeiger ist = siebenstellig.
.
"Eingabe" ist eine lokale Variable, die auf dem Stack angelegt wird.
Der mit New allozierte Speicher liegt dagegen auf dem Heap.
Der Stack wächst von oben nach unten, der Heap aber von unten nach oben.
Heap und Stack sind also unterschiedliche Speicherbereiche.

Zitat:

Es erschließt sich mir nicht, warum die Adresse eines Zeigers in einer Variable gespeichert werden soll, obwohl der Zeiger selber die Möglichkeit bietet sich selber auszulesen.
.
Wie stellst Du Dir denn vor zunächst einen Speicherbereich für den Text zu allozieren und anschließend den Text in diesem zu speichern, wenn Du die Adresse des Speicherbereiches nicht irgendwo speicherst?

Sherlock 11. Sep 2019 14:09

AW: Pointeradresse auslesen
 
Ich hoffe doch sehr, die Diskussion ist akademischer Natur. Pointer und Hantiererei mit ihnen (dazu gehört auch die drollige Pointerarithmetik) ist in einer guten Objektorientierten Sprache (ja, auch Delphi gehört dazu) weggekapselt. Durch falschen Behandlung von Pointern (von Speicherverwaltung über Fehladressierungen zu Pufferüberläufen) geht viel zu viel schief, das vermeidbar wäre. Pointer braucht man heutzutage nur noch in extremen Ausnahmefällen wie Aufrufe ungekapselter OS-Methoden oder auch Treibergeschichten.

Sherlock

paul.kunig 11. Sep 2019 15:23

AW: Pointeradresse auslesen
 
Hallo Klaus,

wieso Delphi 5? Wurde nicht von mir eingetragen.

In der Signatur steht doch Delphi 10 Seattle!

Zitat:

Was aber aus #1 nicht hervorgeht.
Ich habe im ersten Thread die komplette Routine hineingeschrieben.
Daraus geht eindeutig hervor, dass es sich um einen Typisierten Zeiger handelt, der meiner Meinung nach im Heap gespeichert wird.

Zitat:

Ja, wenn "Eingabe" als ^String deklariert ist, ist das so.
Ja, ist im ersten Thread klar erkennbar.
Bitte Beitrag richtig lesen, um weitere Verwirrung meinerseits zu vermeiden.

Zudem schreibst du in deiner ersten Antwort, dass
Delphi-Quellcode:
IntToStr(Integer(Eingabe)) + #13#10 + // Adresse des mit New allozierten Speicherbereichs
,

wobei die beiden anderen Aufrufe(@ und Addr()) für Adresswiedergabe zuständig sind.

Also noch einmal:
Wenn "Eingabe" ein Typisierter Zeiger ist, sollte folgendes gelten/funktionieren.

Eingabe^ = Ausgabe des Speicherinhaltes/abgelegten Wertes
IntToStr(Integer(@Eingabe)) = Ausgabe der Speicheradresse
IntToStr(Integer(Addr(Eingabe))) = Ausgabe der Speicheradresse
IntToStr(Integer(Eingabe)) = ? (ohne Dereferenzierung)

Hierbei ist noch folgendes zu erwähnen.
Der zurückgegebene Wert aus IntToStr(Integer(Eingabe)) entspricht genau dem Wert, der in Überwachte Ausdrücke/Lokale Variablen im Feld Wert angezeigt wird, lediglich von Hexadezimal zu Integer umgewandelt.

Was gibt IntToStr(Integer(Eingabe)) zurück, wenn, wie in diesem Fall, Eingabe ein Zeiger ist?

Gruß

freimatz 11. Sep 2019 16:40

AW: Pointeradresse auslesen
 
Mit "New(Eingabe)" machst Du einen pointer auf dem Heap. ok.
Du weist Eingabe jedoch nichts zu, in dem Fall ist das IMHO dann undefniert. Eingabe zeigt also irgendwohin.
Mit "Eingabe^ := Edit1.Text;" behandelst du dann das irgendwo als einen String und schreibst da etwas rein.

Wenn Du wirklich die Speicheradresse des Zeigers haben willst, dann wäre das bei dir 3. und 4.
Es nutzt dir aber rein gar nichts wenn du "den Wert des Eingabefeldes im Heap speichern" willst.

paul.kunig 11. Sep 2019 16:54

AW: Pointeradresse auslesen
 
Wieso weise ich nichts zu?
Der Inhalt(Wert) des Eingabefeldes wird unter der Speicheradresse des Zeigers abgelegt.

@ und Addr() sind laut Delphi für die Ausgabe der Speicheradresse vorgesehen, richtig.

Aber was gibt IntToStr(Integer(Eingabe)) zurück, wenn, wie in diesem Fall, Eingabe ein Zeiger ist?
Ist die Frage so schwer, drücke ich mich falsch aus oder kann ich mein Anliegen nicht klar darstellen?

freimatz 11. Sep 2019 17:20

AW: Pointeradresse auslesen
 
ok, ich habe da etwas falsch verstanden. Mit New weisst Du Eingabe schon etwas zu.

Schau mal auf http://docs.embarcadero.com/products...ystem_New.html

Da steht "The size of the allocated memory block corresponds to the size of the type that P points to.". Weisst du wieviel das ist? Sicher nicht genug um immer alles von deinem Eingabefeld zu speichern.

Was IntToStr(Integer(Eingabe)) zurück gibt kann ich dir gerade nicht sagen. Das könnte davon abhängen ob Du für 32-Bit oder 64-Bit compilierst und wie Integer implementiert ist. Unsere Umstellung auf 64-Bit ist schon länger her und ich habe das vergessen. Da ich nie einen Pointer auf einen Integer caste (weils einfach schlecht ist) brauche ich das auch nicht. (Und nachzuschauen bin ich zu faul)

paul.kunig 11. Sep 2019 17:31

AW: Pointeradresse auslesen
 
Das ist völlig irrelevant, ob der Speicherplatz ausreicht. Es ist lediglich ein Test zum Verständnis von Zeigern.
Wenn ich die Speicheradresse eines Zeigers ausgeben will, muss ich wohl in einen Integer casten, da ich einen Zeiger nicht anzeigen kann.

Noch einmal die Frage:
Was gibt IntToStr(Integer(Eingabe)) zurück, wenn, wie in diesem Fall, Eingabe ein Zeiger ist?

Amateurprofi 12. Sep 2019 01:07

AW: Pointeradresse auslesen
 
@Paul.Kunig:

Zitat:

wieso Delphi 5? Wurde nicht von mir eingetragen.
In der Signatur steht doch Delphi 10 Seattle!
Ja, in der Signatur steht Delphi 10 Seattle
Aber ganz oben in #1 steht: "Delphi-Version: 5"

Amateurprofi 12. Sep 2019 01:35

AW: Pointeradresse auslesen
 
Zitat:

Noch einmal die Frage:
Was gibt IntToStr(Integer(Eingabe)) zurück, wenn, wie in diesem Fall, Eingabe ein Zeiger ist?
Wie ich schon in #2 schrieb : Die Adresse des mit New allozierten Speicherbereichs.

Da freimatz "für 64 Bit Compilieren" ins Spiel brachte:
Es wäre besser IntToStr(NativeInt(Eingabe)) zu schreiben, denn unter 64Bit hat ein Pointer 8 Bytes.
Wenn du unter 64Bit Eingabe nach Integer castest kriegst du nur die unteren 4 Bytes der Adresse,
dagegen, wenn du nach NativeInt castest kriegst du unter 32Bit 4 Bytes und unter 64Bit 8 Bytes.

Amateurprofi 12. Sep 2019 01:51

AW: Pointeradresse auslesen
 
Zitat:

Zitat von freimatz (Beitrag 1445756)
ok, ich habe da etwas falsch verstanden. Mit New weisst Du Eingabe schon etwas zu.

Schau mal auf http://docs.embarcadero.com/products...ystem_New.html

Da steht "The size of the allocated memory block corresponds to the size of the type that P points to.". Weisst du wieviel das ist? Sicher nicht genug um immer alles von deinem Eingabefeld zu speichern.

Was IntToStr(Integer(Eingabe)) zurück gibt kann ich dir gerade nicht sagen. Das könnte davon abhängen ob Du für 32-Bit oder 64-Bit compilierst und wie Integer implementiert ist. Unsere Umstellung auf 64-Bit ist schon länger her und ich habe das vergessen. Da ich nie einen Pointer auf einen Integer caste (weils einfach schlecht ist) brauche ich das auch nicht. (Und nachzuschauen bin ich zu faul)

@freimatz:
Ich hab auch anfänglich gedacht, dass das problematisch sein könnte.
Tatsächlich werden mit New(Eingabe) nur 4 Bytes (ich bin bei 32Bit) auf dem Heap reserviert.
Aber: mit
Code:
Eingabe^ := Edit1.Text;
wird nicht einfach die Zeichenkette zu Eingabe^ kopiert, sondern es wird ein neuer String erzeugt. An Eingabe^ steht dann die Adresse des neu erzeugten Strings also 4 Bytes.

bcvs 12. Sep 2019 07:38

AW: Pointeradresse auslesen
 
Zitat:

Zitat von Amateurprofi (Beitrag 1445729)
Zunächst mal:
Wir sprechen über Delpi 5, wenn ich #1 richtig interpretiere, also String = ShortString.

Auch wenn es hier nicht relevant ist:
<nostalgiemodus>
Delphi 1 : String = ShortString
Delphi 2..2007 : String = AnsiString
</nostalgiemodus>

freimatz 12. Sep 2019 07:51

AW: Pointeradresse auslesen
 
@Amateurprofi: Hm, ja, richtig, daran habe ich nicht gedacht. Also ist der String selber schon ein Pointer - auf dieses komische Konstrukt wo vorne die Grösse und der Refenzzähler gespeichert ist. Dann klappt das trotzdem so, auch wenn es keinen Sinn macht.
<Klugscheiss>Soweit ich weiss wird jedoch bei der Zuweisung der String nicht kopiert sondern erstmal nur die Referenz bis sich einer der beiden ändert.</Klugscheiss>

samso 12. Sep 2019 07:52

AW: Pointeradresse auslesen
 
Zitat:

Zitat von paul.kunig (Beitrag 1445757)
Das ist völlig irrelevant, ob der Speicherplatz ausreicht. Es ist lediglich ein Test zum Verständnis von Zeigern.
Wenn ich die Speicheradresse eines Zeigers ausgeben will, muss ich wohl in einen Integer casten, da ich einen Zeiger nicht anzeigen kann.

Noch einmal die Frage:
Was gibt IntToStr(Integer(Eingabe)) zurück, wenn, wie in diesem Fall, Eingabe ein Zeiger ist?

Leider hast Du Dir zur Erforschung von Zeigern einen Kandidaten ausgesucht, der die Sache kompliziert macht. Ein String ist bereits eine Zeiger. D.h. ^String ist ein Zeiger auf einen Zeiger. Ich würde vorschlagen, dass Du die Sache vielleicht zunächst mal etwas einfacher gestaltest:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Eingabe: ^Integer; // für die Variable "Eingabe" wird Platz auf dem Stack reserviert
begin
  New(Eingabe); // reserviert Platz für den Integer im Speicher
  Eingabe^ := 123; // der reserviert Platz wird mit einem Wert gefüllt

  ShowMessage(IntToStr(Eingabe^) + #13#10 +  // Erwartete Ausgabe "123"
  IntToStr(Integer(Eingabe)) + #13#10 +      // Erwartete Ausgabe: Wert des Zeigers auf "123"
  IntToStr(Integer(@Eingabe)) + #13#10 +     // Erwartete Ausgabe: Adresse der Variablen "Eingabe" (die Adresse auf dem Stack)
  IntToStr(Integer(Addr(Eingabe)))          // wie vorherige Zeile
  );

  Dispose(Eingabe); // gibt den Platz für den Integer wieder frei
end;

samso 12. Sep 2019 08:05

AW: Pointeradresse auslesen
 
Zitat:

Zitat von paul.kunig (Beitrag 1445695)

Aus welchem Grund sollte die Variable "Eingabe", die ja ein Zeiger ist, erneut eine Speicheradresse bekommen?

Gruß
Paul

Weil der Wert einer Variablen irgendwo gespeichert werden muss. Deshalb hat jede Variable eine Speicheradresse. In Deinem Fall wird der Wert der Variable auf dem Stack gespeichert. Wenn Du noch tiefer einsteigen willst, dann musst Du Dich mit der CPU beschäftigen.

Amateurprofi 12. Sep 2019 10:36

AW: Pointeradresse auslesen
 
Zitat:

Zitat von bcvs (Beitrag 1445821)
Zitat:

Zitat von Amateurprofi (Beitrag 1445729)
Zunächst mal:
Wir sprechen über Delpi 5, wenn ich #1 richtig interpretiere, also String = ShortString.

Auch wenn es hier nicht relevant ist:
<nostalgiemodus>
Delphi 1 : String = ShortString
Delphi 2..2007 : String = AnsiString
</nostalgiemodus>

Richtig, da hab ich was durcheinander gebracht.

paul.kunig 13. Sep 2019 12:02

AW: Pointeradresse auslesen
 
Zuerst einmal Danke für die vielen Antworten.

Jedoch lüftet sich der Schleier nur sehr langsam.

IntToStr(Eingabe^) = Dereferenzierung des Zeigers. Ausgabe des unter der Adresse abgelegten Wertes.

IntToStr(Integer(Eingabe)) // Erwartete Ausgabe
Welche Ausgabe? Es handelt sich um einen Zeiger!

IntToStr(Integer(@Eingabe)) Adresse auf dem Stack.
Warum Adresse des Stacks? Es geht doch um die Adresse des reservierten Speicherplatzes auf dem Heap!

Meines Wissens nach wird der Heap benutzt, wenn größere Datenstrukturen verwendet werden.
Da der Stack in seiner Größe sehr beschränkt ist, weicht man mit Zeigern auf den Heap aus.

Das heißt doch, dass die lokal angelegte Variable lediglich die Adresse des Zeigers, der auf den Heap zeigt, speichert.

Somit müsste man folgende Werte aus der lokalen Variable auslesen können:
1) Adresse der lokalen Variable auf dem Stack
2) Wert der Variable, der in diesem Fall lediglich die Adresse des Zeigers, der auf den Heap zeigt, darstellt.

Ist diese Adresse 4 bzw.8 Byte groß?
Wenn ja, wofür brauchen wir dann den Zeiger, der ja die gleiche Größe hat?

Nach dieser Aufbereitung komme ich zu folgendem Schluss:
IntToStr(Integer(Eingabe))
gibt die eigentliche Adresse des Zeigers auf den Heap zurück, da dies der abgelegte/gespeicherte Wert in der lokalen Variable ist.

IntToStr(Integer(@Eingabe)) als auch
IntToStr(Integer(Addr(Eingabe)))
gibt die Adresse der lokalen Variable zurück, für die im Stack Speicher reserviert wurde, um die Adresse des Zeigers zu speichern.

Dies kommt mir logisch vor, widerspricht aber der bisherigen Dokumentation, in der gesagt wird, dass @ und Addr() die Adresse des Zeigers wiedergeben.
Abschließend sei gesagt, dass nicht näher erläutert ist, welcher Zeiger gemeint ist, da auch die lokale Variable im Hintergrund lediglich ein Zeiger ist.

Gruß und Danke an alle

Dennis07 20. Sep 2019 15:28

AW: Pointeradresse auslesen
 
Nimm statt Integer(MeinZeiger) besser
Delphi-Quellcode:
NativeInt(MeinZeiger)
oder noch besser dessen Alias
Delphi-Quellcode:
IntPtr(MeinZeiger)
. Das funktioniert nicht nur unter Win32, sondern auch Win64 und anderen Plattformen.

p80286 21. Sep 2019 20:40

AW: Pointeradresse auslesen
 
Zitat:

Zitat von paul.kunig (Beitrag 1446000)

Dies kommt mir logisch vor, widerspricht aber der bisherigen Dokumentation, in der gesagt wird, dass @ und Addr() die Adresse des Zeigers wiedergeben.

@ und Addr() liefern beide die Speicheradresse (Pointer) der angesprochenen Variablen.
Mit New(mypointer) reservierst Du Speicher auf dem Heap entsprechend dem Typ auf den mypointer zeigen soll. Weiterhin wird in mypointer die Startadresse des reservierten Speichers abgelegt.

Gruß
K-H

@Sherlock
Gut gebrüllt Löwe. Aber wenn jemand wissen will was es mit Pointern und dem Heap auf sich hat ist das eigentlich positiv zu werten, denn ungesundes Halbwissen auf diesem Gebiet ist tödlich.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:24 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz