2

Is there any better way to convert vector of string to the vector of chars with zero terminator between strings.

So if I have a vector with the following strings "test","my","string", then I want to receive one vector of chars: "test\0my\0string\0".

At this moment this code works fine, but is there any better (more beautiful) solution?

std::vector<std::string> string_array = {"test", "my", "string"};
std::vector<char> buffer_temp;
for (auto &str : string_array)
{
    for (auto &chr : str)
    {
        buffer_temp.push_back(chr);
    }
    buffer_temp.push_back('\0');
}
moooeeeep
  • 31,622
  • 22
  • 98
  • 187
Serbin
  • 803
  • 12
  • 27

2 Answers2

1

Directly copying the string data might be faster for long strings.

 std::vector<std::string> string_array = {"test", "my", "string"};
 int size = 0;
 for (auto &str : string_array)
 {
     size += str.size()+1;
 }

 char * buffer = new char[size];
 int cursor = 0;
 for (auto &str : string_array)
 {
     memcpy(&buffer[cursor], str.data(), str.size());
     cursor += str.size()+1;
     buffer[cursor-1] = '\0';
 }
Loamsiada
  • 444
  • 3
  • 11
  • I would write `std::vector buffer(size);` and `size_t cursor;`. You can also write `memcpy(&buffer[cursor], str.c_str(), str.size()+1);` to copy the zero terminator as well. (In *theory*, `.c_str()` can allocate a new buffer, but no actual implementation does this.) – Martin Bonner supports Monica Jun 29 '17 at 06:49
  • 1
    You should not copy into the raw char data of a string object (there is a reason why it is const char*), this is why I prefer a char array. – Loamsiada Jun 29 '17 at 06:58
1

Never forget the std::vector::insert method with which your example can be simplified as follows:

std::vector<std::string> string_array = { "test", "my", "string" };
std::vector<char> buffer_temp;

for(auto& s : string_array)
    buffer_temp.insert(buffer_temp.end(), s.c_str(), s.c_str() + s.size() + 1);

The std::string::c_str returns a pointer to a null-terminated character array, so you don't have to append an extra '\0' to the end of each element coming from your string_array.


Responding to comments below, you can use std::string iterators as well, and because the std::string has random-access iterator you can do the following:

for(auto& s : string_array)
    buffer_temp.insert(buffer_temp.end(), s.begin(), s.end() + 1);
Akira
  • 4,385
  • 3
  • 24
  • 46
  • 1
    If you use stringstream, you can access the char array directly via ss.str().data(). There is no need to copy it to buffer_temp. – Loamsiada Jun 29 '17 at 07:33
  • I've removed the `std::stringstream` example since there is no need to it if the desired delimiter is `'\0'`. – Akira Jun 29 '17 at 08:33
  • 2
    You should change that to `{ buffer_temp.insert(buffer_temp.end(), s.begin(), s.end()); buffer_temp.push_back('\0'); }` - just because it looks more innocent. – moooeeeep Jun 29 '17 at 09:27