2012-12-29 5 views
6

Der folgende Code wird wie erwartet in meinem System ausgeführt, aber ich bin mir nicht sicher, ob die P Variable garantiert denselben Wert hat, nachdem MyArray[0] auf einen neuen Wert geändert wird.Delphi: Wird ein temporärer PChar garantiert denselben Wert zu haben, nachdem eine vom PChar angezeigte Stringvariable geändert wurde?

procedure Test; 
var 
    MyArray: array of string; 
    P : PChar; 

begin 
    SetLength(MyArray, 2); 
    MyArray[0] := 'ABCD'; 
    MyArray[1] := '1234'; 

    // Is P guaranteed to have the same value all the time? 
    P := PChar(MyArray[0]); 

    MyArray[0] := MyArray[1]; 
    MyArray[1] := P; 

    WriteLn(MyArray[0]); 
    WriteLn(MyArray[1]); 
end; 

Antwort

13

Ihr Code ist technisch ungültig. Es läuft nur aufgrund eines Implementierungsdetails, auf den man sich nicht verlassen sollte.

Schauen wir uns den entsprechenden Abschnitt des Codes einen Blick:

P := PChar(MyArray[0]); 
MyArray[0] := MyArray[1]; 
MyArray[1] := P; 

Zuerst haben wir P Punkt auf das erste Zeichen von MyArray [0] zu machen. Dann weisen wir MyArray [0] zu. An diesem Punkt gibt es keinen Grund für den Zeichenfolgenpuffer, auf den P zeigt, um am Leben zu bleiben. Keine String-Variable verweist darauf. Seine Referenzzählung ist auf Null gegangen und sollte deshalb freigegeben werden. Das macht die nachfolgende Verwendung von P ungültig.

In welchem ​​Fall wird der Code ausgeführt? Weil die Zeichenfolgen, die Sie verwenden, Literale sind. Und so werden sie mit der Referenzzählung gleich -1 gespeichert und umgehen die normalen Heap-Allokationsroutinen, die von Strings verwendet werden. Aber wenn Sie String-Werte verwenden, die keine Literale sind, dann würde das, was ich im obigen Absatz beschreibe, passieren. Und ich erwarte, dass Ihr realer Code keine Literale verwendet.

So ist Ihre eigentliche Frage etwas strittig. Der P-Zeiger zeigt nur auf einen Speicherblock. Es zeigt auf den gleichen Speicherblock, bis Sie den Zeiger ändern. Wenn Sie den Inhalt des Speicherblocks ändern, wird P diese Änderungen anzeigen, wenn Sie es de-referenzieren. Es ist nur ein Zeiger wie jeder andere Zeiger.

Sie müssen vorsichtig mit einer PChar-Variable sein. In Ihrer Verwendung ist es ein nicht verwalteter Zeiger auf ein Compiler-verwaltetes Objekt. Das bietet viel Spielraum für Fehler und Sie sind in die Falle gegangen. Wenn Sie eine Kopie einer Zeichenfolge wünschen, kopieren Sie diese in eine andere Zeichenfolgenvariable.

+2

@David_Heffernan, wow, das ist eine umfassende Erklärung. Vielen Dank. Übrigens, ich verwende mein Codebeispiel nicht oben in meinen Projekten. Es ist nur ein Testcode, den ich gemacht habe, um das PChar-Mysterium zu verstehen. :-) – Astaroth

+2

@Astaroth Guter Artikel über PChars: http://rvelthuis.de/articles/articles-pchars.html – Torbins

2

Es scheint, dass Typ Casting von einer Zeichenfolge zu PChar ist anders als seine Adresse. Siehe den Code unten, es wird die Adresse der Zeichenfolge nehmen.

procedure Test; 
var 
    MyArray: array of string; 
    P : ^String; 

begin 
    SetLength(MyArray, 2); 
    MyArray[0] := 'ABCD'; 
    MyArray[1] := '1234'; 

    // take the pointer 
    P := @MyArray[0]; 

    WriteLn(MyArray[0]); 
    WriteLn(MyArray[1]); 
    WriteLn(P^); 

    // when content of array changes, P^ will change as well 
    MyArray[0] := 'HELLO'; 
    WriteLn(P^); 
end; 
+2

Ja, PChar und^string sind komplett anders. –

Verwandte Themen