2012-12-29 3 views
6

Il seguente codice viene eseguito come previsto nel mio sistema, ma non sono sicuro che la variabile Psia garantita a affinché lo stesso valore dopo MyArray[0] venga modificato in un nuovo valore.Delphi: È possibile che un PChar temporaneo abbia lo stesso valore dopo aver modificato una variabile di stringa puntata dal PChar?

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; 

risposta

13

Il codice è tecnicamente non valido. Funziona solo a causa di un dettaglio di implementazione che non dovrebbe essere invocato.

Diamo uno sguardo alla sezione pertinente di codice:

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

Prima facciamo il punto P al primo carattere di MyArray [0]. Quindi assegniamo a MyArray [0]. A questo punto non c'è motivo per il buffer delle stringhe che P punta a essere mantenuto in vita. Nessuna variabile stringa si riferisce ad essa. Il suo conteggio di riferimento è andato a zero, e quindi dovrebbe essere deallocato. Che rende invalido l'uso successivo di P.

In tal caso, perché viene eseguito il codice? Perché le stringhe che usi sono letterali. Quindi vengono memorizzati con un conteggio di riferimento uguale a -1 e ignorano le normali routine di allocazione dell'heap utilizzate dalle stringhe. Ma se si dovessero usare valori stringa che non erano letterali, allora quello che descrivo nel paragrafo precedente si sarebbe verificato. E mi aspetto che il tuo vero codice non usi letterali.

Quindi la tua domanda è in qualche modo discutibile. Il puntatore P punta solo a un blocco di memoria. Resta puntato allo stesso blocco di memoria finché non si modifica il puntatore. Se modifichi il contenuto del blocco di memoria, P vedrà quelle modifiche se la de-referenzia. È solo un puntatore come qualsiasi altro puntatore.

È necessario fare attenzione utilizzando una variabile PChar. Nel tuo utilizzo, è un puntatore non gestito in un oggetto gestito dal compilatore. Ciò fornisce un sacco di possibilità di errori e sei caduto nella trappola. Se vuoi una copia di una stringa, prendine una copia in un'altra variabile stringa.

+2

@David_Heffernan, wow, questa è una spiegazione completa. Grazie mille. A proposito, non uso il mio esempio di codice sopra nei miei progetti. È solo un codice di test che ho fatto per capire il mistero PChar. :-) – Astaroth

+2

@Astaroth Buon articolo su PChars: http://rvelthuis.de/articles/articles-pchars.html – Torbins

2

Sembra che il casting di tipo da una stringa a PChar sia diverso rispetto al suo indirizzo. Vedere il codice qui sotto, prenderà l'indirizzo di stringa.

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

Sì, PChar e^string sono completamente diversi. –

Problemi correlati