2015-01-23 15 views
7

Il problema viene da un esercizio su C++ Primer 5th Edition:Come inizializzare elegantemente il vettore <char *> con stringa letterale?

scrivere un programma per assegnare gli elementi da un elenco di puntatori char * a stringhe di caratteri in stile C per un vettore di stringhe.

---------------- Domanda Oringinal ------------

Prima cerco il seguente modo un po 'diretta:

vector<char *> vec = {"Hello", "World"}; 
vec[0][0] = 'h'; 

Ma compilazione del codice ottengo un avvertimento:

temp.cpp:11:43: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] 
    vector<char *> vec = {"Hello", "World"}; 
             ^

e l'esecuzione del ./a.out ho un

Segmentation fault (core dumped) 

Penso che sia perché provo a scrivere su un const char. Così provo in un altro modo:

char s1[] = "Hello", s2[] = "World"; 
vector<char *> vec = {s1, s2}; 
vec[0][0] = 'h'; 

Questa volta è OK. Ma sembra un po 'noioso. C'è un altro modo elegante per inizializzare un vettore con stringhe letterali?

+4

Non è possibile modificare il contenuto di una stringa letterale. Si prega di usare 'std :: vector ' ('std :: string' può essere costruito da una stringa letterale) [esempio live] (http://coliru.stacked-crooked.com/a/e0a7821f557b64b8) – Borgleader

+3

I valori letterali delle stringhe sono' array of n const char', puoi trovare maggiori dettagli [qui] (http://stackoverflow.com/q/21529194/1708801). La conversione era ok in C ma non è consentita in C++, esattamente a causa del problema con il tentativo di modificarli che è un comportamento non definito. –

+0

@Borgleader So che è meglio usare il vettore ma l'esercizio su primer C++ mi chiede di convertire un vettore nel vettore . Quindi mi chiedo come inizializzarlo. – Warbean

risposta

4

Ecco un modo:

template <size_t N> 
void append_literal(std::vector<char*>& v, const char (&str)[N]) { 
    char* p = new char[N]; 
    memcpy(p, str, N); 
    v.push_back(p); 
} 

std::vector<char*> v; 
append_literal(v, "Hello"); 
append_literal(v, "World"); 

Basta ricordarsi di:

void clear(std::vector<char*>& v) { 
    for (auto p : v) delete[] p; 
} 

Anche se dalla formulazione della questione, sintatticamente è lo stesso lavoro in entrambi i casi, se si trattava di un vector<const char*> come se fosse a vector<char*> comunque (non stai modificando la fonte quando stai copiando, quindi non importa se tu potresti modificare la fonte), quindi mi limiterei all'esercizio come se tu avessi appena fatto:

std::vector<const char*> v{"Hello", "World!"}; 
+0

Oh, è molto più noioso di quanto mi aspettassi. Ma stimolante. Grazie. – Warbean

5

penso che il char vs const char differenza doesn importa molto in questo compito.

Per la copia reale, utilizzare un costruttore di riempimento con argomenti iteratore:

vector<const char*> vc = {"hello","world"}; 
vector<string> vs(vc.begin(), vc.end()); 

Consulta l'working example.

Se c'è un bisogno per i caratteri modificabili nella fonte, basta usare la seconda versione che hai postato:

char s1[] = "Hello", s2[] = "World"; 
vector<char *> vec = {s1, s2}; 

Supplemento: Gli argomenti di principale, argc e argv, sono una ottimo esempio di

un elenco di puntatori char * per le stringhe di caratteri stile C

Vedere how argc and argv get translated into a vector of string.

+0

Ma voglio un vettore con array di caratteri modificabili. – Warbean

+0

Perché * modificabile * nell'array sorgente?Questo non sembra essere trattato esplicitamente nella descrizione del compito, immagino che si concentri sul trasferimento di C-string nel nuovo mondo del C++? – Wolf

+0

Ho pensato che il suo utilizzo potrebbe essere più generale. Forse ho bisogno di concentrarmi sul trasferimento come dici tu. – Warbean

0

Si potrebbe provare qualcosa di simile:

// utility function to create char*'s 
template<std::size_t Size> 
char* make_rptr(const char (&s)[Size]) 
{ 
    char* rptr = new char[Size]; 
    std::strcpy(rptr, s); 
    return rptr; 
} 

int main() 
{ 
    // initialize vector 
    std::vector<char*> v {make_rptr("hello"), make_rptr("world")}; 

    // use vector 
    for(auto&& s: v) 
     std::cout << s << '\n'; 

    // ... 

    // remember to dealloacte 
    for(auto&& s: v) 
     delete[] s; 
}