2016-04-22 51 views
11

Ho this code che funziona come previsto:Come memorizzare un const char * in un char *?

#define MAX_PARAM_NAME_LEN 32 

const char* GetName() 
{ 
    return "Test text"; 
} 

int main() 
{ 
    char name[MAX_PARAM_NAME_LEN]; 
    strcpy(name, GetName());  

    cout << "result: " << name << endl; 
} 

Se mi piacerebbe memorizzare il risultato a un char * (perché alcune funzioni all'interno di un framework che sto utilizzando l'uso solo char * come input) senza utilizzare il strcpy (per praticità e leggibilità del codice e apprendimento), come potrei fare? Tenendo in const, questo funziona bene:

const char* name; 
name = GetName(); 

ma ho ancora const.

Cercando di utilizzare solo char*:

char* name; 
name = GetName(); 

ottengo invalid conversion from 'const char*' to 'char*'. Qual è la migliore abitudine per questo tipo di conversione?

+5

Cosa vuoi fare? Se non vuoi cambiare la stringa, il primo idioma ti serve e non usa memoria extra; se vuoi cambiare la stringa devi copiare il suo contenuto altrove (quindi hai bisogno di strcpy o simili). – SJuan76

risposta

9

return "Test text"; restituisce un puntatore ad un sola lettura stringa letterale.

Se stai usando una funzione che prende un char* come input, e si dispone di un const char* (ad esempio una stringa di sola lettura letterale), allora si dovrebbe fornire una copia completa della stringa a partire da quel const char* a tali funzioni.

Altrimenti si rischia un comportamento non definito in fase di esecuzione se una funzione tenta di modificare una stringa di sola lettura.

Quello che attualmente è adeguato; partendo dal presupposto che non si può lavorare con std::string. (Se si possibile lavoro con std::stringe tutte le funzioni quadro prendere un ingresso const char*, quindi suggerirei tua refactoring il codice per utilizzare un std::string, e passare l'uscita del metodo c_str() su quella classe string al tuo quadro funzioni.)

Infine, se alcune delle vostre funzioni quadro richiede un char* allora si potrebbe sempre costruire da soli una piccola classe di adattatori:

class Adapter 
{ 
public: 
    Adapter(const& Adapter) = delete; /*don't try to copy me please*/ 
    Adapter& operator=(const Adapter&) = delete; /*don't try to copy me please*/ 
    Adapter(const char* s) : m_s(::strdup(s)) 
    { 
    } 
    ~Adapter() /*free memory on destruction*/ 
    { 
     ::free(m_s); /*use free to release strdup memory*/ 
    } 
    operator char*() /*implicit cast to char* */ 
    { 
     return m_s; 
    } 
private: 
    char* m_s; 
}; 

Poi per una funzione void foo(char* c), è possibile chiamare foo(Adapter("Hello"/*or any const char* */)); e foo può fare come piace con lo char* incorporato nel provvisorio anonimo! Potresti anche migliorare questa classe per prendere un costruttore su un char* dove in quel caso viene presa solo una copia superficiale del puntatore (e il distruttore non cancella la memoria).

+0

Cosa succede se voglio "copiare" il contenuto di 'const char *' in un 'char *' (quindi, senza specificare una dimensione fissa)? Non conosco la dimensione di quel carattere *, poiché in seguito concentro 'altri caratteri. – markzzz

+0

Oh aspetta. Vedo che posso usare 'char * name;' e piuttosto che 'strcpy (name, GetName());' pure. Fondamentalmente, ho ottenuto una stringa non definita dalla lunghezza, che servirà il mio compito. È corretto farlo? – markzzz

+1

@paizza No. Usa qualcosa come 'std :: string name = GetName();' quindi passa 'name.c_str()' a qualsiasi funzione framework che si aspetta un 'const char *'. – Andrew

-1

In C++, il tipico modo per "drop const" è quello di utilizzare const_cast<>:

char *name = const_cast<char*>(GetName()); 

Questo è, naturalmente, visto di buon occhio, brutto e potenzialmente pericoloso, dal momento che è davvero possibile che GetName() restituisce un puntatore a qualcosa che non dovrebbe essere modificato, e quindi vai e darti il ​​permesso di cambiarlo. In questo caso, è un buon modo per essere molto difficili da trovare bug.

Una soluzione alternativa consiste nell'utilizzare un std::string come area di attesa temporanea; vorrà dire copiare la stringa, ma che potrebbe essere accettabile prestazioni-saggio:

std::string s(GetName()); 
char *name = s.c_str(); 

Ovviamente questo funziona solo se name non è mantenuto intorno quando s va fuori portata. In questo caso, avrai una forma di livello di archiviazione delle stringhe persistente.

+3

Non sta rimuovendo const da un comportamento non definito 'const char *'? – Default

+1

Se posso chiedere, perché stai suggerendo qualcosa che è disapprovato, senza dare altri suggerimenti? – Default

+0

@Default Perché questo era ciò che il poster voleva sapere come fare, e non posso sapere con certezza che sarà male nella situazione in questione. – unwind

15

L'abitudine migliore per questo tipo di conversione è l'utilizzo di std::string in tutto il codice. Dal momento che il quadro che si sta utilizzando prende const char* come input, si può sempre passare i risultati di c_str() chiamata sul std::string:

std::string GetName() { 
    return "Test text"; 
} 

int main() { 
    std::string name = GetName(); 
    int res = external_framework_function(name.c_str()); 
    cout << "result: " << res << " for " << name << endl; 
} 

un lontano secondo miglior sta utilizzando const char* nel codice:

const char* name = GetName(); 

Dato che il framework che stai usando prende const char* sei bravo anche qui.

Se è necessario un puntatore non const, non c'è modo di copiare la stringa. È possibile effettuare una funzione che fa per voi, ma si dovrebbe rimanere responsabile di liberare le copie che si ottiene da esso:

char* copy(const char* orig) { 
    char *res = new char[strlen(orig)+1]; 
    strcpy(res, orig); 
    return res; 
} 
... 
char *name = copy(GetName()); 
... 
delete[] name; 
-2

Si potrebbe lanciare esplicitamente. (char*) getName(). Ma probabilmente non dovresti. Perché il bit const significa qualcosa come "prometti di non cambiarlo". Quindi, se ho una funzione void foo(const char* string), sono sicuro: "dammi un puntatore a una stringa. Non lo cambierò". E se dichiari una variabile const char* string = "hello"; stai dicendo, questa stringa non dovrebbe essere cambiata. E poiché tu fai questa promessa, il compilatore lo sa e può rendere il tuo codice più efficiente. Questo è il motivo per cui:

const char* a = "hello"; 
const char* b = "hello"; 
(a==b); //is probably true 

il compilatore sa che non cambierai a o b in modo che rende loro puntano allo stesso indirizzo, quindi ha solo per memorizzare un "hello" stringa. Se ora vai a cambiare a, anche b cambia, e questo non è quello che volevi.

Per farla breve, se sei assolutamente sicuro che la funzione che la tua chiamata non modifica la stringa, puoi espressamente lanciarla. (o meglio, cambia la funzione in (const char*) se è la tua).
Se non sei sicuro, dovrai fare una copia. (Come stai già facendo con strcpy()).

+2

Perché stai suggerendo il piatto calchi pericolosamente pericolosi? L'unico modo corretto per ottenere una stringa C non const da una stringa letterale C++ è di copiarlo. Qualsiasi tentativo di modificare la versione del cast non-const è UB. Si prega di non suggerire un metodo che (quasi certamente) si tradurrà in un comportamento del programma difficile da diagnosticare lungo la linea. – Andrew