10
votes

I understand that using vector is a good way to store binary data when using C++ and the STL. However for my unit tests I'd like to initalise the vector using a const char* C string variable.

I'm attempting to use a variant of the code found here - Converting (void*) to std::vector<unsigned char> - to do this:

const char* testdata = "the quick brown fox jumps over the lazy dog.";

unsigned char* buffer = (unsigned char*)testdata;
typedef vector<unsigned char> bufferType;

bufferType::size_type size = strlen((const char*)buffer);
bufferType vec(buffer, size);

However the VC++ compiler is not happy with the line initialising the vector, stating:

error C2664: 'std::vector<_Ty>::vector(unsigned int,const _Ty &)' : cannot convert parameter 1 from 'char *' to 'unsigned int'

I appreciate the extreme n00bity of this question and am fully prepared for much criticism on the code above :)

Thanks in advance, Chris

4
You are much better off using: std::vector<std::string> vec; vec.push_back("the quick brown fox jumps over the lazy dog."); - Alok Save
The code under test will eventually be used to handle binary data, hence the preference for vector<unsigned char>. For the tests, I'd like to initialise it using const char* data. - Mr Chris
You can get the underlying char data simply by using std::string::c_str(), and you save a lot of potential problems of using raw pointers.Not a bad deal IMO. - Alok Save
This was my original approach, but was worried that using c_str() might throw an additional \0 byte at the end of the array. Good for strings, not good for binary data. - Mr Chris

4 Answers

16
votes

It should be

bufferType vec(buffer, buffer + size);

not

bufferType vec(buffer, size);
3
votes

std::transform is useful for just this sort of problem. You can use it to "transform" one piece of data at a time. See documentation here:

http://www.cplusplus.com/reference/algorithm/transform/

The following code works in VS2010. (I created a std::string from your const char* array, but you could probably avoid that if you really wanted to.)

#include <algorithm>
#include <vector>

int main(int, char*[])
{
  // Initial test data
  const char* testdata = "the quick brown fox jumps over the lazy dog.";

  // Transform from 'const char*' to 'vector<unsigned char>'
  std::string input(testdata);
  std::vector<unsigned char> output(input.length());
  std::transform(input.begin(), input.end(), output.begin(),
    [](char c)
    {
      return static_cast<unsigned char>(c);
    });

  // Use the transformed data in 'output'...


  return 0;
}
3
votes

Here is what worked for me:

// Fetch data into vector
std::vector<char> buffer = <myMethod>.getdata();

// Get a char pointer to the data in the vector
char* buf = buffer.data();

// cast from char pointer to unsigned char pointer
unsigned char* membuf = reinterpret_cast<unsigned char*>(buf);            

// now convert to vector<unsigned char> buffer
std::vector<unsigned char> vec(membuf, membuf + buffer.size()); 

// display vector<unsigned char>   
CUtils::<myMethodToShowDataBlock>(vec);      
0
votes

What you intended to do seems to be something like:

buffertype vec(testdata, next(testdata, strlen(testdata)));

There is no need for the intermediate buffer variable. The conversion from char to unsigned char will happen implicitly.

Note that this does not grab the terminating '\0' character from testdata. So if you wanted to be able to do something like: cout << vec.data() you wouldn't be able to. If you want that you could do: buffertype vec(testdata, next(testdata, strlen(testdata) + 1)) or you may just want to consider doing:

basic_string<unsigned char> vec(testdata, next(testdata, strlen(testdata)));

Which will preserve a hidden '\0'. Because this is not a string you won't be able to do, cout << vec but cout << vec.data() will work. I've created a Live Example of each of these.