Reputation: 165
I'm trying to convert a std::vector<std::string>
to a NULL terminated array of C-style strings (char *
). Is it possible without copying with new
/malloc
?
Basically, I want to convert vec back into the EXACT SAME thing as arr without new/malloc.
#include <string>
#include <vector>
#include <stdio.h>
using namespace std;
void print(const char **strs)
{
const char **ptr = strs;
while(*ptr) {
printf("%s ", *ptr);
++ptr;
}
}
void print(std::vector<std::string> &strs) {
for(auto iter = strs.begin(); iter != strs.end(); ++iter) {
printf("%s ", iter->c_str());
}
}
void main()
{
const char *arr[] = { "a", "b", "c", "d", "e", "f", NULL };
vector<string> vec;
const char **str = arr;
while(*str) {
vec.push_back(*str);
++str;
}
vec.push_back((char *) NULL); //Doesn't work
//print(vec);
print((const char **) &vec[0]);
}
Upvotes: 1
Views: 3358
Reputation: 254431
You'll need to build the array of pointers yourself, and you will need dynamic allocation if the size isn't known at compile time. (In this example, you could infer it from sizeof arr
; but I'm assuming that arr
isn't available when you need to reconstruct it).
You can use pointers to the strings managed by the vector, so you won't need to allocate any memory for them.
So you can get the array you need thusly:
std::vector<char const *> vec2;
vec2.reserve(vec.size()+1); // optional, but might improve efficiency
for (auto const & str : vec) {
vec2.push_back(str.c_str());
}
vec2.push_back(nullptr);
print(vec.data());
Upvotes: 3
Reputation: 56479
It's not possible just by setting a pointer to the beginning of that vector, because vector<string>
is not sequential characters as you expect.
addr1 addr2 addr3
^ ^ ^
| | |
+--------+--------+--------+----
| | | | | | |
| std:: | std:: | std:: |
+----> | string | string | string | ...
| | | | |
| +--------+--------+--------+----
|
|
|
vector<string>
addr1
, addr2
and addr3
are random addresses in memory.
So, the solution is iterating over the items, read the strings and characters and put them in your continues array.
Upvotes: 5
Reputation: 129324
Ok, so you can't store a "NULL" inside a std::vector<std::string>
, which I think is what you are aiming to do.
The whole point with std::vector
is that it keeps track of number of entries in std::vector::size()
However, if you really need to have a something that you can pass to a function like your print, then you could do something like this:
vector<const char *> v;
for(auto iter = vec.begin(); iter != vec.end(); ++iter) {
v.push_back(iter->c_str());
}
v.push_back(NULL);
print(&v[0]);
Upvotes: 0
Reputation:
Is it possible without copying with new/malloc?
If your C++ compiler supports variable-length arrays as an extension, then it is. Else you will have to use dynamic memory allocation.
std::vector<std::string> vec;
// initialize `vec', etc.
const char *c_strings[vec.size()];
size_t idx = 0;
for (std::vector<std::string>::iterator it = vec.begin(); it != vec.end(); it++) {
c_strings[idx++] = it->c_str();
}
Upvotes: 0