2014-09-25 12 views
12

Ho una variabile vector<std::string>. Ho bisogno di passarlo su un metodo che accetta char** come parametro di input.convertire il vettore <string> in char ** C++

come fare questo? Se possibile, ho bisogno di passare uno scrivibile.

Update 1: In uno strumento per creare un metodo di servizio, io do parametri come std :: vector, ma imposta automaticamente la qualificazione come &, il che significa che la mia definizione di metodo generato dallo strumento sarà come:

std::string SvcImpl::myMethodname (const std::string par1, const std::vector<  std::string >& par2, const std::vector<std::string>& par3) 
{ 

} 

Questo metodo viene chiamato automaticamente con i valori nel parametro passato. Ora da dentro questo metodo ho intenzione di chiamare un metodo in una DLL in una cartella lib che assomiglia a:

int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue); 

per par1 -> che sto passando (char *) par1.c_str()

Ho bisogno di sapere come passare le variabili per par2 e par3 e per pRetValue. I valori per par2 e par3 sono disponibili in vettoriale ma l'ultimo parametro pRetValue è un parametro di output che ho bisogno di restituirlo come std :: string.

scusate se sono molto confuso o faccio domande molto semplici.

+1

quindi l'operazione dovrebbe essere su '* writable', assumendo ** scrivibile accetta il tuo char ** param. –

+1

Penso che sarà necessario produrre un nuovo 'std :: vector ' per memorizzare gli indirizzi di tutti i dati della stringa. – Galik

+0

Che cosa fa esattamente questo metodo che si sta passando? – Wlerin

risposta

18

E 'possibile risolvere il problema senza copiare tutte le std::strings fino a quando la funzione di non modifica il passato in char**. Altrimenti non vedo altra alternativa che copiare tutto in una nuova struttura char ** `(vedi il secondo esempio).

void old_func(char** carray, size_t size) 
{ 
    for(size_t i = 0; i < size; ++i) 
     std::cout << carray[i] << '\n'; 
} 

int main() 
{ 
    std::vector<std::string> strings {"one", "two", "three"}; 
    std::vector<char*> cstrings; 
    cstrings.reserve(strings.size()); 

    for(size_t i = 0; i < strings.size(); ++i) 
     cstrings.push_back(const_cast<char*>(strings[i].c_str())); 

    // Do not change any of the strings here as that will 
    // invalidate the new data structure that relies on 
    // the returned values from `c_str()` 
    // 
    // This is not an issue after C++11 as long as you don't 
    // increase the length of a string (as that may cause reallocation) 

    if(!cstrings.empty()) 
     old_func(&cstrings[0], cstrings.size()); 
} 

ESEMPIO 2: Se la funzione deve modificare il passato nei dati:

void old_func(char** carray, size_t size) 
{ 
    for(size_t i = 0; i < size; ++i) 
     std::cout << carray[i] << '\n'; 
} 

int main() 
{ 
    std::vector<std::string> strings { "one", "two", "three"}; 
    char** cstrings = new char*[strings.size()]; 

    for(size_t i = 0; i < strings.size(); ++i) 
    { 
     cstrings[i] = new char[strings[i].size() + 1]; 
     std::strcpy(cstrings[i], strings[i].c_str()); 
    } 

    // Now the function can do what it likes (within the bounds) 
    // with the passed in structure 

    old_func(cstrings, strings.size()); 

    // clean up memory 

    for(size_t i = 0; i < strings.size(); ++i) 
     delete[] cstrings[i]; 

    delete[] cstrings; 
} 

EDIT5: optato per una soluzione più semplice per la post codice C++ (thnx a BeyelerStudios) ha aggiunto una soluzione che consente alla funzione di modificare i dati passati.

+0

Buono, anche se nella seconda versione avrei utilizzato un vettore o almeno un unique_ptr per contenere l'array di puntatori e qualche tipo di funzione scope_exit per eliminare i puntatori all'interno. Se una qualsiasi delle singole allocazioni di stringhe fallisce qui, tutte le precedenti e l'array di puntatori sono trapelate. –

+0

nel commento del tuo codice, hai scritto che "questo non è un problema dopo C++ 11". puoi spiegare perché? – bernie

+1

@lefenzy Ho modificato il commento perché non era del tutto accurato. Ma prima di 'C++ 11' non vi è alcuna garanzia che il puntatore restituito da' c_str() 'punti ai dati reali della stringa (potrebbe essere un buffer temporaneo). Dopo 'C++ 11' è garantito puntare ai dati reali delle stringhe. Viene invalidato solo se si * aumenta * la lunghezza della stringa. – Galik

7

La risposta di Galik ha una serie di problemi di sicurezza. Ecco come lo farei in Modern C++:

#include <iostream> 
#include <string> 
#include <vector> 

void old_func(char** carray, std::size_t size) 
{ 
    for(std::size_t i(0); i < size; ++i) 
     std::cout << carray[i] << '\n'; 
} 

void other_old_func(const char** carray, std::size_t size) 
{ 
    for(std::size_t i(0); i < size; ++i) 
     std::cout << carray[i] << '\n'; 
} 

int main() 
{ 
    { 
     std::cout << "modifiable version\n"; 
     std::vector<std::string> strings{"one", "two", "three"}; 
     std::vector<char*> cstrings{}; 

     for(auto& string : strings) 
      cstrings.push_back(&string.front()); 

     old_func(cstrings.data(), cstrings.size()); 

     std::cout << "\n\n"; 
    } 
    { 
     std::cout << "non-modifiable version\n"; 
     std::vector<std::string> strings{"four", "five", "six"}; 
     std::vector<const char*> cstrings{}; 

     for(const auto& string : strings) 
      cstrings.push_back(string.c_str()); 

     other_old_func(cstrings.data(), cstrings.size()); 
     std::cout << std::endl; 
    } 
} 

No di gestione della memoria disordinato o brutto const_cast s.

Live on Coliru.

Uscite:

modifiable version 
one 
two 
three 


non-modifiable version 
four 
five 
six 
Problemi correlati