Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

convert vector<string> into char** C++

Tags:

c++

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.

like image 665
Mohamed Iqzas Avatar asked Sep 25 '14 06:09

Mohamed Iqzas


Video Answer


2 Answers

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_casts.

Live on Coliru.

Outputs:

modifiable version one two three   non-modifiable version four five six 
like image 28
caps Avatar answered Sep 21 '22 09:09

caps


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.

like image 143
Galik Avatar answered Sep 24 '22 09:09

Galik