convert vector<string> into char** C++
I have a vector<std::string>
variable. I need to pass it onto a method which accepts char**
as an input parameter.
how to do this ? If possible I need to pass a writable one.
Update 1: In a tool for creating a service method, i give parameters as std::vector, but it sets automatically the qualifier as &, which means my method definition generated by the tool will look as:
std::string SvcImpl::myMethodname ( const std::string par1, const std::vector< std::string >& par2, const std::vector< std::string >& par3 )
{
}
This method gets called automatically with values in the patameter passed. Now from inside this method I'm going to call a method in a dll in a lib folder which looks like:
int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);
for par1 --> I'm passing (char*)par1.c_str()
I need to know how to pass variables for par2 and par3 and for pRetValue. values for par2 and par3 are available in vector but the last parameter pRetValue is an output parameter that i need to return it as std::string.
sorry if i am very confusing or asking very basic questions.
It is possible to solve the problem without copying out all the std::strings
as long as the function does not modify the passed in char**
. Otherwise I can see no alternative but to copy out everything into a new char**` structure (see second example).
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());
}
EXAMPLE 2: If the function must modify the passed in data:
void old_func(char** carray, size_t size)
{
for(size_t i = 0; i < size; ++i)
std::cout << carray[i] << '\n';
}
int main()
{
{
// pre C++11
std::vector<std::string> strings {"one", "two", "three"};
// guarantee contiguous, null terminated strings
std::vector<std::vector<char>> vstrings;
// pointers to rhose strings
std::vector<char*> cstrings;
vstrings.reserve(strings.size());
cstrings.reserve(strings.size());
for(size_t i = 0; i < strings.size(); ++i)
{
vstrings.emplace_back(strings[i].begin(), strings[i].end());
vstrings.back().push_back('\0');
cstrings.push_back(vstrings.back().data());
}
old_func(cstrings.data(), cstrings.size());
}
{
// post C++11
std::vector<std::string> strings {"one", "two", "three"};
std::vector<char*> cstrings;
cstrings.reserve(strings.size());
for(auto& s: strings)
cstrings.push_back(&s[0]);
old_func(cstrings.data(), cstrings.size());
}
}
NOTE: Revised to provide better code.
Galik's answer has a number of safety issues. Here is how I would do it 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 messy memory management or nasty const_cast
s.
Live on Coliru.
Outputs:
modifiable version
one
two
three
non-modifiable version
four
five
six
The top rated answers for this question expect you to pass in a size with your char** parameters. But in method_to_be_called() there is no way to pass in a size for par2 and par3 so these lists of c-style strings probably expect to be null terminated. In other words the last string (char*) in the list of strings (char **) needs to be a null pointer. This is a common paradigm in many c libraries.
int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);
The most expedient way around this is probably to go with a more c-style answer.
//directly create char** par2
std::vector<std::string> par2Vect{"one", "two", "three"};
char ** par2 = (char**) malloc( sizeof(char*)*(par2Vect.size() + 1) );
for(size_t i = 0; i < par2Vect.size(); ++i)
{
par2[i] = strdup(par2Vect[i].c_str());
}
// set the last entry to null to signify the end of the list
par2[par2Vect.size()] = nullptr;
// call your library
method_to_be_called(..., par2,...);
// delete par2
for(size_t i = 0; i < par2Vect.size(); ++i)
{
// free memory for each c-style string
free(par2[i]);
}
// free memory for outer char* array
free(par2);