Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Pointer


Thomas_1110 - Di 24.06.03 20:04
Titel: Pointer
Hallo Forum

Eines was mich beschäftigt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var Puffer: Pointer;
begin
  GetMem(Puffer, 255);
  PChar(Puffer^) :='Testtext';
  Showmessage(PChar(Puffer^));
  Freemem(Puffer, 255);
end;

funktioniert.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var Puffer: Pointer;
begin
  GetMem(Puffer, 255);
  GetLogicalDriveStrings(255, PPuffer);
  Showmessage(PChar(Puffer^));
  Freemem(Puffer, 255);
end;

gibt bei mir eine Fehlermeldung. ändere ich es so

Delphi-Quelltext
1:
Showmessage(PChar(Puffer));                    

dann funktionierts.

Weiteres noch: wie kann ich aus Puffer am besten die einzelnen Strings auslesen. Verwende Delpie 3 pro.

Gruß Thomas

Moderiert von user profile iconTino: Code- durch Delphi-Tags ersetzt.


AndyB - Di 24.06.03 20:25

Zitat:
PChar(Puffer^) :='Testtext';

Weißt du, was du da machst? Anscheinend nicht, denn damit greiftst du auf einen Speicherbereich zu, dessen Adresse du durch das Konvertieren der ersten 4 Zeichen des neu reservierten Speichers in einen PChar erhältst. Das das zu einer Schutzverletzung führen sollte, ist dir doch klar. Aber anscheinend hast du Glück und somit eine Zeitbombe geschrieben.

Die richtige Konvertierung wäre PChar(Puffer) (ohne das "^"-Zeichen)


Thomas_1110 - Di 24.06.03 20:51

Zitat:
Weißt du, was du da machst? Anscheinend nicht, denn damit greiftst du auf einen Speicherbereich zu, dessen Adresse du durch das Konvertieren der ersten 4 Zeichen des neu reservierten Speichers in einen PChar erhältst.

Ist das nur bei PChar so oder auch bei anderen Typen?
Zitat:
Die richtige Konvertierung wäre PChar(Puffer) (ohne das "^"-Zeichen)

Komischerweise bekomme ich grad hier die Schutzverletzung :?: Wenn ich die Pointer richtig verstanden hab steht in Puffer die Adresse. Setzt ich ein ^ ran kann ich lesen und schreiben darin. Da in meinem Fall Puffer untypisiert ist, muß ich ihn vorher typisieren.
Also

Delphi-Quelltext
1:
PChar(Puffer^) :=                    

das funktioniert jedenfalls bei mir

Gruß Thomas


AndyB - Di 24.06.03 21:13

Bei PChars kannst du nicht einfach den Zuweisungsoperator (":=") benutzen. Dieser würde nämlich die Zeiger-Adresse auf die Adresse setzen, an der der Compiler den String abgelegt hat.

Dein Code muss also

Delphi-Quelltext
1:
StrCopy(PChar(Puffer), ''Testtext');                    

lauten.

Um noch einmal auf die Typenkonvertierung zurückzukommen.

Puffer -> $1000
An Speicheradresse $1000 steht: $00 01 02 03 04 05

Mit PChar(Puffer^) machst du nun folgendes:

Delphi-Quelltext
1:
2:
var P: PChar;
  P := $00 01 02 03;

Damit zeigt der neugewonnene Zeiger P nicht auf den reservierten Speicherplatz, sondern wild in den Arbeitsspeicher.


Bei PChar(Puffer^) := 'Testtext'; überschreibst du die ersten 4 Bytes des Speichers, auf den Puffer zeigt. Dadurch wird aus den oben genannen $00 01 02 03 die Adresse an der der Compiler 'Testtext' abgelegt hat. Es ist dann natürlich kar, dass du mit ShowMessage(PChar(Puffer^)) die Adresse von 'Testtext' übergibst. Damit brauchst du gar nicht 255 Bytes reservieren, wenn du sowieso nur 4 davon nutzt.

Das 1. Beispiel kannst du auch so lösen:

Delphi-Quelltext
1:
2:
3:
4:
5:
var Puffer: PChar;
begin
  Puffer := 'Testtext'// Adresse von 'Testtext' dem Zeiger Puffer zuweisen
  ShowMessage(Puffer);
end;





Bei deinem 2. Beispiel machst du bei der Ausgabe den selben Fehler (vom Schreibfehler PPuffer mal abgesene).

Die Funktion GetLogicalDriveStrings() schreibt die Daten in den ihr übergebenen PChar, wobei hier zu beachten ist, dass die einzelnen Teilstring mit einem #0-Zeichen von einander getrennt sind. Nach dem letzen Teilstring kommt ein #0#0, dass den gesamten String abschließt.
Wenn du nun PChar(Puffer) an ShowMessage übergibst, gibt diese nur den ersten Laufwerksbuchstaben aus, da das erste #0 als Stringende betrachtet wird. Das noch weitere Laufwerksbuchstaben folgen, kann ShowMessage nicht wissen. Dies muss der Programmierer erledigen.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
var
  P: PChar;
  S: string;
begin
  P := StrAlloc(255 + 1);
  try
    GetLogicalDriveStrings(255, P);
    while P^ <> #0 do
    begin
      SetString(S, P, StrLen(P));
      P := StrEnd(P) + 1// auf nächsten Laufwerksbuchstaben setzen.

      ShowMessage(S);
    end;
  finally
    StrDispose(P);
  end;
end;


Thomas_1110 - Di 24.06.03 21:45

Danke für die Mühe, da muß ich noch viel lernen zum Thema Pointer :roll:
Bei deinem Beipiel muß man noch den Zeiger wieder auf den Ursprung setzten, sonst gibts am Schluß eine Fehlermeldung.
Gruß Thomas


Motzi - Fr 27.06.03 19:13

Thomas_1110 hat folgendes geschrieben:
Danke für die Mühe, da muß ich noch viel lernen zum Thema Pointer :roll:

Dann schau dir mal das Pointer-Tutorial an (hier in der Tutorial-Sparte).

@AndyB: was PChars und deren Typecastings betrifft so führt Delphi im Hintergrund oft noch zusätzliche Schritte aus! Bestes Beispiel sind die 3 verschiedenen Methoden einen String in einen PChar zu casten:

Delphi-Quelltext
1:
2:
3:
PChar(String)
@String[1]
Pointer(String)

mit jeder dieser Methoden kann man einen String in einen PChar casten, aber immer mit einem andren Ergebnis!


Thomas_1110 - Fr 27.06.03 20:16

Zitat:
Dann schau dir mal das Pointer-Tutorial an (hier in der Tutorial-Sparte).

Danke für den Tip, hab ich schon gelesen, ist aber nur ein Teil von dem was das Thema zu bieten hat.

Gruß Thomas


Motzi - Fr 27.06.03 20:25

Das stimmt schon, aber die wichtigsten Sachen werden darin bereits erklärt (referenzieren, dereferenzieren, ...) der Rest sind Details die man eh nur per learning by doing wirklich lernen kann...