std::vector<std::string> to char* array
Solution 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.
Solution 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.
Solution 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.
Comments
-
Christopher DuBois almost 4 years
I have a
std::vector<std::string>
that I need to use for aC
function's argument that readschar* foo
. I have seen how to convert astd::string
tochar*
. As a newcomer toC++
, I'm trying to piece together how to perform this conversion on each element of the vector and produce thechar*
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>
. -
Nicol Bolas over 12 yearsYou need to show how to delete that array, particularly since it's so complicated. Don't forget to use
delete[]
. -
Christopher DuBois over 12 yearsDoesn't c_str() return a const char? Will that be a problem if I just need a char*? (I've included the exact interface in the comments.)
-
Christopher DuBois over 12 yearsQuick question: Why is the delete [] vc portion necessary if we're using a std::vector?
-
Nawaz over 12 years@Christopher: Because we're using
new
to allocate memory forchar*
, that is why we're doingdelete vc[i]
. But we're not allocating memory forchar**
, hence we're not doingdelete vc
. -
Mankarse over 12 yearsThis leaks if the
new
in thefor
throws. It would be much better to use astd::vector
. -
Mankarse over 12 yearsThis code will not compile. It is neither legal nor safe to assign a pointer-to-const to a pointer-to-non-const.
-
Mankarse over 12 yearsThis code leaks if the new in
convert
throws. It would be much better to use astd::vector<char>
. -
Nawaz over 12 years@Christopher: See my answer. Now it has more explanation.
-
Nawaz over 12 years@Mankarse:
std::vector<char>
where? In convert function? Local variable? -
Mankarse over 12 yearsThe convert function should return a
std::vector<char>
rather than achar*
. If achar*
is required later then&vc[0]
can be used. If it is really necessary to be able to produce achar**
then a separate vector that does not own the underlying memory should be used. If ownership of thechar*
must be moved into the C code then an RAII container should be used that automatically allocates and deallocates thechar*
appropriately, and thechar*
should be released from that container only when the ownership is transfered. -
Lightness Races in Orbit over 12 years"Returning a local object isn't accepted by many people" // No, this is rubbish. Returning a reference or pointer to a local object isn't accepted by the language or by compilers. But this is not the same.
-
Lightness Races in Orbit over 12 yearsAnd not only is this code non-valid, but even if you'd actually casted away the
const
ness, it would be a horrendously silly thing to do. -
Admin over 12 yearsThanks Tomalak for your corrections and comments, please don't be too harsh, it's another idea, how to make it safer still depends on the OP's actual coding experience...
-
don bright almost 12 yearsyou could also do std::vector<const char *>cStrArray( origVector.size()+1, NULL); and then in the iterator use cStrArray[i]=origVector[i].c_str(); This can help with functs like execv(). But as the note above says, we could use more info about ModelInitialize.
-
Legend over 7 yearsThanks for your answer! Is there anyway I can convert the vector<string> to char* so I can copy it elsewhere? In your approach, it looks like vc.size() is 4 but the strings have a varying length. In that case, how I convert the char** to a char*? Should I remember the individual string lengths elsewhere?
-
Nawaz over 7 years@Legend:
vs.size()
has nothing to do with the length of the individual stringsvs
contains. Also, read about null-terminated strings. Note that a valid c-string has to be null-terminated which helps you compute the length of any c-string. -
463035818_is_not_a_number over 6 years"const char* is also the same as char*, only different in the const_ness" that is as helpful as stating that "apples are the same as oranges, just different"