convert std vector to char and viceversa [duplicate] - c++

This question already has an answer here:
Convert std::vector to array
(1 answer)
Closed 7 years ago.
I have a library function from which I should pass same data types to the main application .
Thus my question is - how do I pass a std::vector<char> to a C style function that expects char*. Here is what I have tried
// function to apply on char
void somefunction (char* c_buf, int* c_buf_len)
// main function
typedef std::vector<char> Buf;
void (Buf& buf)
{
// first convert `buf` to char and call function
somefunction(char_buf, char_buf_len)
// Now convert buf to vector and do something with it..
}

You cannot convert a vector to char. They're completely unrelated types. Good news is that you seem to need a pointer to a character buffer and a vector<char> is exactly that. You get the pointer to the begginning of its storage by taking the address of the first element (&buf[0]) or by saying buf.data(). buf.size() will give you (you guessed it!) the size of the buffer. That's all you need to call somefunction.

To pass a std::vector<char> to a function that expects a char *, you can
1) Pass the address of the first element in the vector. The only caveat is that using this method requires that the vector is not empty.
if (!buf.empty())
somefunction(&buf[0], buf.size());
2) If using C++ 11 use the data() method for the vector. In C++ 11, using data guarantees that it will work with an empty vector.
somefunction(buf.data(), buf.size());

Like this:
void (Buf& buf)
{
int len = buf.size();
somefunction(&buf[0], &len);
// ...
}

int len = buf.size();
somefunction(&buf[0], &len);
You can do that because (From n2798 (draft of C++0x)):
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized)
constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage
management is handled automatically, though hints can be given to improve efficiency. The elements of a
vector are stored contiguously, meaning that if v is a vector where T is some type other
than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

Related

Reversing Array Without Using Array Size

It is relatively easy to reverse an array given a pointer to the array and the size of the array.
But my question is: Is it possible to reverse the array given just a pointer to the array?
( in C++ btw)
EDIT
This was a question apparently asked in an interview at Lockheed Martin. See here
In general the answer is NO.
It is only possible for so called terminated arrays like NULL-terminated char array:
void reverse(char* str)
{
int end = -1;
int front = -1;
while (str[++end] != NULL);
while (--end > ++front)
{
char temp = str[end];
str[end] = str[front];
str[front] = temp;
}
}
No it is not possible. If you dont know the size of your array then you cant reverse it.
It can be possible if you define a "terminator" for your array element type, like \0 used for char arrays. You should always end the array with that value, otherwise you'll obtain runtime errors. But it's always better to use the size or avoid arrays and use vectors since you're using c++ and not c.
Nope. Without knowing the size, you cannot use the iterators to reverse it and without using iterators and not knowing the size, it wouldnt be possible to reverse that particular array. You would have to declare another array, copy the contents from the first array into the new array, and perform the content reverse on the new array.

STD::Vector- write directly to the internal array

Is the following code ok?:
std::vector<char> var;
size_t requiredSize;
getenv_s(&requiredSize, NULL, 0, "Something");
if (requiredSize == 0)
{
return ENV_NOT_EXIST;
}
if(var.size() < requiredSize)
var.resize(requiredSize);
// Get the value of the environment variable.
getenv_s(&requiredSize, &var[0], requiredSize, "Something");
std::string str(var.begin(),var.end());
If this code is OK, can someone please explain me how the begin() and the end() values of the var vector are updated? it looks like this code changes directly the internal array of the vector, not over the std::vector api - so how these values are updated to the actual size?
std::vector guarantees data to be stored contiguously, so writing to data, as long as you do not overrun the end is perfectly fine:
From the C++11 standard section 23.3.6.1.1:
The elements of a vector are stored contiguously, meaning that if v is
a vector where T is some type other than bool, then it
obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
However, note that resizing the vector might move the data and invalidate iterators.
Unfortunately, the standard does not require std::vector<T>::iterator to be a raw pointer type (although it usually is). So, you cannot portably use std::vector<T>::begin() to access the first element. There is std::vector<T>::data(), which returns a pointer to the first element and which can be used for code that expects raw c-arrays.
I suggest to rewrite your call like this:
getenv_s(&requiredSize, var.data(), var.size(), "Something");
if (requiredSize < var.size())
var.resize(requiredSize);

Copying an array into a std::vector

I was searching about this topic and I found many ways to convert an array[] to an std::vector, like using:
assign(a, a + n)
or, direct in the constructor:
std::vector<unsigned char> v ( a, a + n );
Those solve my problem, but I am wondering if it is possible (and correct) to do:
myvet.resize( 10 );
memcpy( &myvet[0], buffer, 10 );
I am wondering this because I have the following code:
IDiskAccess::ERetRead nsDisks::DiskAccess::Read( std::vector< uint8_t >& bufferRead, int32_t totalToRead )
{
uint8_t* data = new uint8_t[totalToRead];
DWORD totalRead;
ReadFile( mhFile, data, totalToRead, &totalRead, NULL );
bufferRead.resize( totalRead );
bufferRead.assign( data, data + totalRead );
delete[] data;
return IDiskAccess::READ_OK;
}
And I would like to do:
IDiskAccess::ERetRead nsDisks::DiskAccess::Read( std::vector< uint8_t >& bufferRead, int32_t totalToRead )
{
bufferRead.resize( totalToRead );
DWORD totalRead;
ReadFile( mhFile, &bufferRead[0], totalToRead, &totalRead, NULL );
bufferRead.resize( totalRead );
return IDiskAccess::READ_OK;
}
(I have removed the error treatment of the ReadFile function to simplify the post).
It is working, but I am affraid that it is not safe. I believe it is ok, as the memory used by the vector is continuous, but I've never seen someone using vectors this way.
Is it correct to use vectors like this? Is there any other better option?
Yes it is safe with std::vector C++ standard guarantees that the elements will be stored at contiguous memory locations.
C++11 Standard:
23.3.6.1 Class templatevector overview [vector.overview]
A vector is a sequence container that supports random access iterators. In addition,itsupports(amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that ifv is avector whereT is some type other than bool, then it obeys the identity&v[n] == &v[0] + n for all0 <= n < v.size().
Yes, it is fine to do that. You might want to do myvet.data() instead of &myvet[0] if it looks better to you, but they both have the same effect. Also, if circumstances permit, you can use std::copy instead and have more type-safety and all those other C++ standard library goodies.
The storage that a vector uses is guaranteed to be contiguous, which makes it suitable for use as a buffer or with other functions.
Make sure that you don't modify the vector (such as calling push_back on it, etc) while you are using the pointer you get from data or &v[0] because the vector could resize its buffer on one of those operations and invalidate the pointer.
That approach is correct, it only depends on the vector having contiguous memory which is required by the standard. I believe that in c++11 there is a new data() member function in vectors that returns a pointer to the buffer. Also note that in the case of `memcpy you need to pass the size in bytes not e size of the array
The memory in vector is guaranteed to be allocated contiguously, and unsigned char is POD, therefore it is totally safe to memcpy into it (assuming you don't copy more than you have allocated, of course).
Do your resize first, and it should work fine.
vector<int> v;
v.resize(100);
memcpy(&v[0], someArrayOfSize100, 100 * sizeof(int));
Yes, the solution using memcpy is correct; the buffer held by a vector is contiguous. But it's not quite type-safe, so prefer assign or std::copy.

How to copy a range of data from char array into a vector?

I've read file contents into a char array, and then read some data of it into a vector.
How can i copy a range of the char array into the vector? both vector and char array is the same type (unsigned char).
Current code goes something like this:
int p = 0;
for(...){
short len = (arr[p+1] << 8) | arr[p+0];
p+=2;
...
for(...len...){
vec.push_back(arr[p]);
p++;
}
}
I would like to improve this by dropping the loop with push_back, How?
Appending something to a vector can be done using the insert() member function:
vec.insert(vec.end(), arr, arr+len);
Of course, there's also an assign(), which is probably closer to what you want to do:
vec.assign(arr, arr+len);
However, reading your question I wondered why you would first read into a C array just to copy its content into a vector, when you could read into a vector right away. A std::vector<> is required to keep its data in one contiguous block of memory, and you can access this block by taking the address of its first element. Just make sure you have enough room in the vector:
std::size_t my_read(char* buffer, std::size_t buffer_size);
vec.resize( appropriate_length );
vec.resize( my_read_func(&vec[0], vec.size()) );
Instead of &vec[0] you could also get the address of the first element by &*vec.begin(). However, note that with either method you absolutely must make sure there's at least one element in the vector. None of the two methods are required to check for it (although your implementation might do so for debug builds), and both will invoke the dreaded Undefined Behavior when you fail on this.

Getting array from std:vector

What is the easiest way of getting a char array from a vector?
The way I am doing is getting a string initialized using vector begin and end iterators, and then getting .c_str() from this string. Are there other efficient methods?
This was discussed in Scott Meyers' Effective STL, that you can do &vec[0] to get the address of the first element of an std::vector, and since the standard constrains vectors to having contiguous memory, you can do stuff like this.
// some function
void doSomething(char *cptr, int n)
{
}
// in your code
std::vector<char> chars;
if (!chars.empty())
{
doSomething(&chars[0], chars.size());
}
edit: From the comments (thanks casablanca)
be wary about holding pointers to this data, as the pointer can be invalidated if the vector is modified.
std::vector<char> chars;
char* char_arr = chars.data(); // &chars[0]