Einzelnen Beitrag anzeigen

jbg

Registriert seit: 12. Jun 2002
3.481 Beiträge
 
Delphi 10.1 Berlin Professional
 
#14
  Alt 30. Aug 2002, 13:19
Code:
[b]function[/b] spiegeln(p: PChar): PChar;
[b]var[/b] test: [b]string;
begin[/b]
  test := [b]string[/b](p);
  ...
  Result := PChar(test);
[b]end[/b];
Um dir mal zu erklären, warum das nicht funktioniert:

Dein Programm ruft spiegeln(PChar(MyString)) auf, dabei wird PChar(MyString) auf dem sog. Stack abgelegt und p zeigt auf die Speicherstelle im Stack, an der PChar(MyString) liegt. (Danach kommt noch die Rücksprungadresse auf den Stack.)
Nun wird Platz auf dem Stack für die lokale Variable test gemacht. In diese kopierst du den PChar, auf den p zeigt und führst deine Umkehrung durch.
Bis jetzt funktioniert alles, doch nun kommt der entscheidende logische Fehler:
Du weist Result nun einen Zeiger (PChar ist ja nur ein Zeiger) auf die Speicheradresse, an der test abgelegt ist, zu. Doch da test eine lokale Variable ist und somit auf dem Stack liegt, zeigt Result auf eine Adresse im Stack.
Durch das end; wird nun aber der von test belegte Stack-Speicher freigegeben, womit Result auf einen bereits freigegebenen Speicherbereich zeigt. Wenn nun ein weiterer Funktionsaufruf nach dem Zurückkehren der spiegeln-Funktion stattfindet (es reicht auch eine einfache Zuweisung von Variablen), dann überschreibt diese die noch auf dem Stack an der Result-"Adresse" liegenden, unveränderten Bytes mit ihren eigenen lokalen Variablen und Parametern.
Deswegen liefert die Funktion nur noch Bytesschrott zurück, der auch noch zum teilweise auch noch aus den "orignal"-Daten bestehen kann (was die Fehlersuche dann eher auf die Funktion selbst ziegt).


Das Problem könntest du z.B. so lösen, dass du den String "in-place" spiegelst (also Eingabe-Parameter = Ausgabe-Parameter):
Code:
[b]procedure[/b] spiegeln(p: PChar);
[b]var[/b] s: [b]string[/b];
[b]begin[/b]
  s := p;
  ...
  StrLCopy(p, PChar(s), StrLen(p)); // Daten in p zurückschreiben
[b]end[/b];

s := 'Dies ist ein Test';
spiegeln(PChar(s));
ShowMessage(s);
Das in-place-Verfahren funktioniert nur, wenn die Länge der Eingabedaten mit der der Ausgabe-Daten übereinstimmt.

Oder um es WinAPI gerecht zu machen:
Code:
[b]function[/b] spiegeln(p: PChar; Buffer: PChar; MaxBufferLen: Integer): Integer;
[b]var[/b] s: [b]string[/b];
[b]begin[/b]
  s := p;
  ...
  [b]if[/b] Buffer <> [b]nil then[/b]
    StrLCopy(Buffer, PChar(s), MaxBufferLen); // Daten in Buffer schreiben
  Result := Length(s); // Rückgabewert = Länge des bearbeiteten Strings
[b]end[/b];

[b]var[/b]
  Buf: PChar;
  BufSize: Integer;
[b]begin[/b]
  s := 'Dies ist ein Test';
  BufSize := spiegeln(PChar(s), nil, 0);
  Buf := StrAlloc(BufSize);
  [b]try[/b]
    spiegeln(PChar(s), Buf, BufSize);
  [b]finally[/b]
    StrDipose(Buf);
  [b]end[/b];
  ShowMessage(s);
[b]end[/b];

[i]// Wenn die max. Aufgabelänge bekannt ist, dann geht das auch so:[/i]
[b]var[/b] Buf: [b]array[/b][0..1024] [b]of[/b] Char;
SetString(s, Buf, spiegeln(PChar(s), Buf, 1024));
ShowMessage(s);
Ein function Xyz: PChar; sollte man nur verwenden, wenn man konstante oder global deklarierte Strings einsetzt. Konstante Strings sind nur Strings, die in '' stehen. Wenn ein + oder ein Funktionsaufruf notwendig sind, dann handelt es sich nicht um konstante Strings, da sie erst zur Laufzeit zusammengesetzt werden müssen. Am einfachsten kann man herausbekommen, ob ein String konstant ist oder nicht, indem man sich selbst nur Fragen muss, könnte man diesen String auch so deklarieren:

const MyString = 'Hier steht der zu "prüfende" String';
  Mit Zitat antworten Zitat