2010-06-16 16 views
5

È possibile creare un letterale stringa modificabile in C++? Ad esempio:Creare una stringa letterale modificabile in C++

char* foo[] = { 
    "foo", 
    "foo" 
}; 
char* afoo = foo[0]; 
afoo[2] = 'g'; // access violation 

Questo produce una violazione di accesso perché le s "foo" sono allocati in memoria di sola lettura (sezione .rdata Credo). C'è un modo per forzare i "foo" nella memoria scrivibile (sezione .data)? Anche attraverso un pragma sarebbe accettabile! (Compilatore Visual Studio)

So che posso fare strdup e un numero di altre cose per aggirare il problema, ma voglio sapere in particolare se posso fare come ho chiesto. :)

+1

No, in base allo standard che modifica un comportamento non definito evocato dalla stringa letterale. Il dato stesso è 'const', anche se si ha un puntatore non-' '' '' '' '' Se lo fai, rischi di avere problemi di esecuzione, di esecuzione o di modifica o persino di patch del compilatore. –

+0

Non ha senso muovere una stringa ** letterale **. Forse è più chiaro con int: come faccio a compilare '5 = 7'? – fredoverflow

+0

Anne, questo non è qualcosa che dovresti fare, ma è possibile in pratica, contro quello che dice lo standard C++. Ho scritto un articolo che spiega come farlo in sistemi UNIX che hanno un'interfaccia di protezione della memoria esposta ai programmi dello spazio utente, [guardalo qui] (http://lazarenko.me/2013/05/01/how-constant -is-a-costante /). –

risposta

1

è possibile creare un array multidimensionale di caratteri:

#include <iostream> 

int main(int argc, char** argv) 
{ 
    char foo[][4] = { 
     "foo", 
     "bar" 
    }; 
    char* afoo = foo[0]; 
    afoo[2] = 'g'; 
    std::cout << afoo << std::endl; 
} 

modo più dettagliato per definire l'array:

char foo[][4] = { 
    {'f', 'o', 'o', '\0'}, 
    {'b', 'a', 'r', '\0'} 
}; 
+2

È ancora possibile utilizzare i letterali stringa, non è necessario specificare tutti i caratteri come valori letterali char. –

+0

@Noah: Grazie per averlo indicato. –

+2

Inoltre, Anne dovrebbe tenere presente che se lo fa in questo modo il 4 deve essere la dimensione della stringa più lunga +1. Usare una classe di stringhe è davvero l'opzione migliore, ma questo è il più vicino a quello che sembra voler ottenere. –

9

Poiché questo è C++, la risposta "migliore" sarebbe utilizzare una classe di stringa (std::string, QString, CString, ecc. A seconda del proprio ambiente).

Per rispondere direttamente alla domanda, non è necessario modificare i valori letterali stringa. Lo standard dice che questo è un comportamento indefinito. Hai davvero bisogno di duplicare la stringa in un modo o nell'altro, altrimenti stai scrivendo C++ non corretto.

+2

+1 per 'std :: string', -1 per strane stringhe non standard. –

+1

@Mike Seymour: Quando a Roma ... – Cogwheel

+2

Per elaborare, se stai usando un framework che ha una propria classe di stringhe, ti renderai la vita più difficile provando ad adattare 'std :: string' nel mix. Quindi "a seconda del proprio ambiente" – Cogwheel

2

Se si memorizza la stringa in una matrice, è possibile modificarla.

Non c'è modo di scrivere "correttamente" nella memoria di sola lettura.

Si potrebbe, ovviamente, smettere di usare stringhe a C.

+0

Correttamente è soggettivo. Correttamente secondo cosa? Secondo l'hardware, c'è un modo abbastanza corretto e diretto per farlo, considerando che non esiste una memoria di sola lettura in quasi tutto l'hardware di base, davvero. –

4

penso che il più vicino si può venire è di inizializzare una pianura char[] (non un char * []) ​​con un letterale:

char foo[] = "foo"; 

Che sarà ancora eseguire una copia ad un certo punto però.

L'unico altro modo per aggirare sarebbe utilizzare le chiamate a livello di sistema per contrassegnare la pagina in cui una stringa letterale risiede come scrivibile. A quel punto non stai davvero parlando di C o C++, stai parlando davvero di Windows (o di qualsiasi sistema su cui stai lavorando). Probabilmente è possibile sulla maggior parte dei sistemi (a meno che i dati non siano realmente nella ROM, ad esempio potrebbe essere il caso su un sistema embedded), ma di sicuro non conosco i dettagli.

Oh, e non dimenticate che nel tuo esempio:

char* foo[] = { 
    "foo", 
    "foo" 
}; 

Dal momento che la standard (C99 6.4.5/6 "letterali stringa"), dice:

E 'specificato se questi array sono distinti purché i loro elementi abbiano i valori appropriati.

Non c'è certezza se i 2 puntatori di quella matrice puntino agli stessi oggetti o separati. Quasi tutti i compilatori avranno quei puntatori che puntano allo stesso oggetto allo stesso indirizzo, ma non sono obbligati e alcune situazioni più complicate di puntatori a stringhe letterali potrebbero avere il compilatore in arrivo con 2 stringhe identiche separate.

Si potrebbe anche avere uno scenario in cui esiste 'all'interno' un'altra stringa letterale:

char* p1 = "some string"; 
char* p2 = "string"; 

p2 può ben essere puntato verso la fine della stringa puntata da p1.

Quindi, se inizi a cambiare i valori letterali stringa con qualche trucco che puoi eseguire su un sistema, potresti finire a modificare involontariamente alcune "altre" stringhe. Questa è una delle cose che un comportamento indefinito può portare con sé.

+0

c'è anche 'char _foo [] =" foo "; char * foo = & _foo [0] ' –

1

Non lo farei. Pertanto, posso solo fornire un brutto scherzo che potresti provare: Ottieni la pagina in cui il tuo letterale costante risiede e non proteggi quella pagina. Vedere la funzione VirtualProtect() per Win32. Tuttavia, anche se funziona, non garantisce il comportamento corretto in ogni momento. Meglio non farlo.

-3

Sì.

(char[]){"foo"} 
+2

Questo evoca un comportamento non definito. –

Problemi correlati