std::vector<std::string> to char* array

吃可爱长大的小学妹 提交于 2019-12-17 22:35:08

问题


I have a std::vector<std::string> that I need to use for a C function's argument that reads char* foo. I have seen how to convert a std::string to char*. As a newcomer to C++, I'm trying to piece together how to perform this conversion on each element of the vector and produce the char* array.

I've seen several closely related SO questions, but most appear to illustrate ways to go the other direction and create std::vector<std::string>.


回答1:


You can use std::transform as:

std::transform(vs.begin(), vs.end(), std::back_inserter(vc), convert);  

Which requires you to implement convert() as:

char *convert(const std::string & s)
{
   char *pc = new char[s.size()+1];
   std::strcpy(pc, s.c_str());
   return pc; 
}

Test code:

int main() {
       std::vector<std::string>  vs;
       vs.push_back("std::string");
       vs.push_back("std::vector<std::string>");
       vs.push_back("char*");
       vs.push_back("std::vector<char*>");
       std::vector<char*>  vc;

       std::transform(vs.begin(), vs.end(), std::back_inserter(vc), convert);   

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            std::cout << vc[i] << std::endl;

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            delete [] vc[i];
}

Output:

std::string
std::vector<std::string>
char*
std::vector<char*>

Online demo : http://ideone.com/U6QZ5

You can use &vc[0] wherever you need char**.

Note that since we're using new to allocate memory for each std::string (in convert function), we've to deallocate the memory at the end. This gives you flexibility to change the vector vs; you can push_back more strings to it, delete the existing one from vs, and vc (i.e vector<char*> will still be valid!

But if you don't want this flexibility, then you can use this convert function:

const char *convert(const std::string & s)
{
   return s.c_str();
}

And you've to change std::vector<char*> to std::vector<const char*>.

Now after the transformation, if you change vs by inserting new strings, or by deleting the old ones from it, then all the char* in vc might become invalid. That is one important point. Another important point is that, you don't need to use delete vc[i] in your code anymore.




回答2:


The best you can do is allocate an std::vector of const char* the same size as your vector. Then, walk each element of the vector, calling c_str() to get the string array and storing it the corresponding element of the array. Then you can pass the pointer to the first element of this vector to the function in question.

The code would look like this:

std::vector<const char *> cStrArray;
cStrArray.reserve(origVector.size());
for(int index = 0; index < origVector.size(); ++index)
{
  cStrArray.push_back(origVector[index].c_str());
}

//NO RESIZING OF origVector!!!!

SomeCFunction(&cStrArray[0], cStrArray.size());

Note that you cannot allow the original vector of strings to be resized between the time you fetch the const char*s from the std::strings, and the time you call the C-function.




回答3:


This should work:

char ** arr = new char*[vec.size()];
for(size_t i = 0; i < vec.size(); i++){
    arr[i] = new char[vec[i].size() + 1];
    strcpy(arr[i], vec[i].c_str());
}

EDIT:

Here's how you would free these data structures assuming vec still has the correct number of elements, if your C function modifies this array somehow you may need to get the size another way.

for(size_t i = 0; i < vec.size(); i++){
    delete [] arr[i];
}
delete [] arr;

EDIT Again:

It may not be necessary to copy the strings if your C function does not modify the strings. If you can elaborate on what your interface looks like I'm sure we could provide you with better help.




回答4:


A C++0x solution, where elements of std::string are guaranteed to be stored contiguously:

std::vector<std::string> strings = /* from somewhere */;
int nterms = /* from somewhere */;

// using std::transform is a possibility depending on what you want
// to do with the result of the call
std::for_each(strings.begin(), string.end(), [nterms](std::string& s)
{ ModelInitialize(&s[0], nterms); }

If the function null terminates its argument, then after the call (s.begin(), s.end()) might not be meaningful. You can post-process to fix that:

s = std::string(s.begin(), std::find(s.begin(), s.end(), '\0'));

A more elaborate version that separately copies each string into a char[]:

typedef std::unique_ptr<char[]> pointer;
std::vector<pointer> args;
std::transform(strings.begin(), strings.end()
               , std::back_inserter(args)
               , [](std::string const& s) -> pointer
{
    pointer p(new char[s.size()]);
    std::copy(s.begin(), s.end(), &p[0]);
    return p;
});

std::for_each(args.begin(), args.end(), [nterms](pointer& p)
{ ModelInitialize(p.get(), nterms); });



回答5:


const char* is also the same as char*, only different in the const_ness, your interface method accepts both const and non-const string.

Doesn't c_str() return a const char? Will that be a problem if I just need a char*?

Yes, it returns a const string and no there should no problem

const char*a="something";
////whatever it is here
const char* retfunc(const char*a)
{
   char*temp=a;
   //process then return temp
}

Returning a local object is n't accepted by many people andthis tiny example is provided as an as-is.




回答6:


The elements of a vector are stored contiguously, so the best and easy way is:

std::vector<char> v;
char* c = &v[0];


来源:https://stackoverflow.com/questions/7048888/stdvectorstdstring-to-char-array

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!