4

This is the opposite of How to convert a vector<char*> to a vector<string>/string question.

I have some legacy routine which works with vector<char*> so I need to transform my vector<string>.

Here is what I come out with:

std::vector<char*> charVec(strVec.size(),nullptr);
for (int i=0; i<strVec.size();i++) {
    charVec[i]= new char(strVec[i].size()+1); 
    charVec[i][strVec[i].copy(charVec[i], strVec[i].size())] = '\0';
}

Is this correct?

Is there a better way to implement it?


p.s. of course at the end I have:

for (int i=0; i<strVec.size();i++) {
    delete charVec[i];
}
Community
  • 1
  • 1
bibi
  • 3,671
  • 5
  • 34
  • 50

5 Answers5

6

A faster way of doing this is

std::vector<const char*> charVec(strVec.size(),nullptr);
for (int i=0; i<strVec.size();i++) {
    charVec[i]= strVec[i].c_str();
}

and then using the resulting vector. This will save a lot of time on memory allocation for large sets of data.

JeremiahB
  • 896
  • 8
  • 15
4

Why are you allocating new buffer for your strings? You are passing a vector of character pointers to a function and finally deleting allocated buffers. It means these buffers are temporary and there is no need to allocate memory for them as far as source vector(vector<string>) exist.

You can easily do this:

std::vector<std::string> vec1 = { "1", "2", "3" };
std::vector<const char*> vec2;

vec2.resize(vec1.size(), nullptr);

std::transform(std::begin(vec1), std::end(vec1), std::begin(vec2), [&](const std::string& str)
{
    return str.c_str();
});
MRB
  • 3,752
  • 4
  • 30
  • 44
  • Or you could replace `vec2.resize()` with `vec2.reserve()` and then use `std::back_inserter(vec2)` as the output iterator. – Remy Lebeau Feb 27 '17 at 19:07
  • @RemyLebeau Of Course, good point. I had forgotten `std::back_inserter`. Thanks for remind. – MRB Feb 27 '17 at 19:12
4

Your new statement looks wrong. You want to allocate an array of char long enough to hold the string. You're allocating a single char whose value is the length of the string. I'm surprised you didn't get compiler warnings about that.

Try this:

std::vector<char*> charVec;
for (const auto &str : strVec) {
  char *charStr = new char[str.size() + 1];
  std::strcpy(charStr, str.c_str());
  charVec.push_back(charStr); 
}

The only drawback here is that, if one of the strings has embedded null characters, nothing beyond those will be copied. But I suspect that a function which takes a vector of char * almost certainly doesn't care about that anyway.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
2

You could simply use string::c_str() to get the string out of a std::string. Read more in How to convert a std::string to const char* or char*?

Or you could just modify a bit the body of the function, but only you know if this is worth it.


Of course as ssell mentions in the comments, keep in mind that with this approach you need not to destroy your strings when you handle them! It's a trade-off, you avoid the copy (so cool), but you need to be careful not reading junk (in case you delete your strings)!

Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • I would not recommend `std::string::c_str` as it isn't safe. If any of his original `std::string` objects are destroyed, the `char*` string will become invalid. It is better to copy over the data as he does in his question and others do in their answers. See [What is std::string::c_str() lifetime?](http://stackoverflow.com/questions/6456359/what-is-stdstringc-str-lifetime). – ssell Feb 27 '17 at 19:04
  • @ssell good point, but I wouldn't go with the "do not touch" directive, I would like more the use with caution, I will update! – gsamaras Feb 27 '17 at 19:05
  • 1
    If he has strict control over the scope, then your answer is the most straight-forward. Just wanted to warn about the potential dangers. – ssell Feb 27 '17 at 19:06
0

vector < string > to vector < const char* > : use c_str()

std::vector<const char*> charVec(strVec.size(), nullptr);
for (int i=0; i<strVec.size(); i++) {
    charVec[i] = strVec[i].c_str();
}

vector < string > to vector < char* > : use &x[0]

std::vector<char*> charVec(strVec.size(), nullptr);
for (int i=0; i<strVec.size(); i++) {
    charVec[i] = &strVec[i][0];
}

Refs: How to convert a std::string to const char* or char*?

mdrafiqulrabin
  • 1,657
  • 5
  • 28
  • 38