I'm trying to fill a vector with integers from an array I have but when I check the contents of the vector all the values are zero.
I'm using vector.push_back() to try and fill the vector so it will be in the same order as the array as I needed it ordered in a specific way.
unsigned char* buffer = new unsigned char[size];
std::vector<unsigned char> *data = new std::vector<unsigned char>(size);
fread(buffer, sizeof(unsigned char), size, f);
for(int transfer = 0; transfer < size; transfer += 1){
std::cout << buffer[transfer];
data->push_back(buffer[transfer]);
std::cout << int(data->at(transfer));
}
fclose(f);
When I print the output I can see that the values aren't zero when they're coming from the buffer array but they are when I read from the data vector. Here is some example output φ0$0.
std::vector has a constructor for this purpose:
std::vector<unsigned char> data(buffer, buffer + size);
newing a vector almost always should be avoided.
Live
The overload of the constructor of std::vector that you are using takes the number of elements to initialize the vector with and initializes these (to 0 in this case).
After the line
std::vector<unsigned char> *data = new std::vector<unsigned char>(size);
*data therefore contains already size elements set to zero.
Then with data->push_back(...) you are adding additional elements after these size elements. You are not overwriting the previous ones.
Either use
std::vector<unsigned char> *data = new std::vector<unsigned char>();
to default-initialize an empty vector, or use
(*data)[transfer] = ...
to set the elements at the given location.
Furthermore your program has undefined behavior if the fread reads less than size bytes into the array. You need to check the number of bytes read from its return value and you are not allowed to access any elements beyond that in data, because you never initialized it.
You can initialize it to zero with:
unsigned char* buffer = new unsigned char[size]{};
If you want to write C++, don't use C library functions like fread, use the facilities provided by <fstream>, i.e. std::ifstream and std::ofstream instead.
Similarly there is no need for dynamic memory allocation here. Declare variables with automatic storage:
unsigned char buffer[size]{};
std::vector<unsigned char> data(size);
and the rest of the syntax also simplifies:
data[transfer] = ...
Finally, as mentioned in the other answer, there is a constructor for std::vector that will perform the whole copy loop for you. Note however that my argument about undefined behavior still applies when using that.
Defining data as automatic array as in
unsigned char buffer[size]{};
works only if size is a compile-time constant. If it is not, then this part of my advice does not apply. However there is no real need to use arrays at all in any case. You can initialize a std::vector of proper size (compile-time constant or not) and provide that as buffer via its .data() method, which returns a pointer to the underlying (continuous) storage:
std::vector<unsigned char> buffer(size);
fread(buffer.data(), sizeof(unsigned char), buffer.size(), f);
You don't need a separate buffer or any dynamic allocation in your code. You can create the std::vector with the desired size and then read from the file directly into the vector. The std::vector::data member function returns a pointer to the vector's underlying array that you can pass to the fread() function
std::vector<unsigned char> vec(size);
fread(vec.data(), sizeof(unsigned char), size, f);
Ideally you'll also check the return value from fread() to know how many elements were read.
Related
I have large array of char
char myCharArray[] = {
0x9B,0x3E,0x34,0x87,0xFD,0x24,0xB4,0x64,0xBA,0x80,0x04,0xFD,
0xDF,0x23,0x41,0xEE,0x00,0x00,0x00,0x00,0xAC,0xF9,0x8F,0x00,
...
}
How to convert myCharArray to vector<byte>
You are allowed to inspect an array of char as an array of std::byte. So the most efficient solution would be:
#include <iterator> // for std::begin / end
std::vector<std::byte> v(
reinterpret_cast<std::byte*>(std::begin(myCharArray)),
reinterpret_cast<std::byte*>(std::end(myCharArray))
);
This way, the vector knows up front how much memory to allocate and it can perform the copy via memcpy or a similar efficient routine instead of copying one byte after the other and having to reallocate multiple times in between.
EDIT:
Note that this code only works, because the return type of std::begin on a native array is guaranteed to be apointer. If myCharArray was e.g. a std::vector<char>, then std::begin/end would return an iterator (which may or may not be a native pointer). In that case, you would e.g. need to use myCharVector.data() and myCharVector.data() + myCharVector.size() to get pointers to the start and end of the array.
std::vector<std::byte> bytes;
for (char &c : myCharArray) {
bytes.push_back(static_cast<std::byte>(c));
}
I want to convert size_t to vector of unsigned chars. This vector is defined as 4 bytes.
Could anybody suggest a suitable way to do that?
Once you've reconciled yourself to the fact that your std::vector is probably going to have to be bigger than that - it will need to have sizeof(size_t) elements - one well-defined way is to access the data buffer of such an appropriately sized vector and use ::memcpy:
size_t bar = 0; /*initialise this else the copy code behaviour is undefined*/
std::vector<uint8_t> foo(sizeof(bar)); /*space must be allocated at this point*/
::memcpy(foo.data(), &bar, sizeof(bar));
There is an overload of data() that returns a non-const pointer to the data buffer. I'm exploiting this here. Accessing the data buffer in this way is unusual but other tricks (using unions etc.) often lead to code whose behaviour is, in general, undefined.
By "convert", I'll assume you mean "copy", since vector will allocate and own its memory. You can't just give it a pointer and expect to use your own memory.
An efficient way to do so which avoids two-stage construction (that causes initialization of the array with zero) is to do this:
auto ptr = reinterpret_cast<uint8_t*>(&the_size);
vector<uint8_t> vec{ptr, ptr + sizeof(size_t)};
Note that sizeof(size_t) is not required to be 4. So you shouldn't write your code assuming that it is.
You could write a generic converter using std::bitset
template <typename T>
std::vector<unsigned char> Type_To_Bit_Vector(T type, char true_char, char false_char){
//convert type to bitset
std::bitset<sizeof(type)*8> bset(type);
//convert bitset to vector<unsigned char>
std::vector<char> vec;
for(int i = 0 ; i < bset.size() ; i++){
if (bset[i]){
vec.push_back(true_char);
}else{
vec.push_back(false_char);
}
}
return vec;
}
You could then get a desired vector representation like so:
auto vec = Type_To_Bit_Vector(size_t(123),'1','0');
I have following in my code:
static unsigned char* table;
...
table = something here;
Now I have to assign this table to variable of type std::vector<unsigned char> and I am unable to do so. I am doing:
unsigned char* buffer = (unsigned char*) table;
std::vector<unsigned char>::size_type size = strlen((const char*)buffer);
std::vector<unsigned char>static rawTable(buffer, buffer + size);
for(ByteBuffer::iterator it=rawTable.begin();it!=rawTable.end();++it)
std::cout << "Raw Table: "<<*it<< std::endl;
I am able to compile the code, but no value is there inside rawTable. Please help!
I have verified that variable table has value. I appreciate any help on this. Thanks.
strlen gives you the length of a string, not the size of an arbitrary memory region. If your table has a '\0' anywhere inside, strlen will find it and stop counting.
Also, by making rawTable a static variable, it will not update its value if buffer or size ever change. static variables are constructed only once.
Also, if this is supposed to be a table of numeric data, you should cast to a numeric non-character type. Otherwise cout may interpret it as ASCII codes.
You have a pointer of type unsigned char* pointing to an array.
Then you want to push every element of the array into a std::vector<unsigned char>, right?
If so, the key is to know the size of the array. You need to know the size beforehand. There's no way to determine the size of the array in the general case with some keyword or function if all that is visible to you is a pointer of type unsigned char*. You need to pass that information along with the pointer somehow.
In the case when the pointer of type unsigned char* points to an array of characters which is null-terminated (e.g. {'f', 'o', 'o', '\0'}), then you can use the C-string function strlen to count the number of characters in the array using only the pointer. However if the array is not null-terminated this will result in undefined behaviour.
When you have the size it's a simple matter to populate the std::vector with the arrays elements:
std::vector<unsigned char> v(arr, arr + size); // arr = pointer to array.
This is why you should use the containers in the standard library instead of raw arrays, as these containers internally keep track of the size and you can always access it with the size() function.
For constant size arrays use std::array. Example:
std::array<unsigned char, 3> arr{'f', 'o', 'o'}; // arr.size() == 3
// Print its contents.
for (auto c : arr) {
std::cout << c << std::endl;
}
I'm reading multiple reports from a HID device into an unsigned char, then trying to copy the data to a std::vector. I'm also writing the data out to a file for hex analysis, whose content appears to be correct when I view it. However, the std::vector doesn't appear to contain the correct data when I dump it to the console.
This is the code:
typedef vector<unsigned char> buffer_t;
buffer_t sendCommand (hid_device *devh, const unsigned char cmd[], int reports) {
unsigned char outbuf[0x40];
buffer_t retbuf(0x40 * reports);
hid_write(devh, cmd, 0x41);
int i;
FILE *file = fopen("test.out", "w+b");
while (i++ < reports) {
hid_read(devh, outbuf, 0x40);
fwrite(outbuf, 1, sizeof(outbuf), file);
retbuf.push_back(*outbuf);
}
fclose(file);
cout << &retbuf[0];
return retbuf;
}
I have a feeling I'm way off the mark here; I'm fairly new to C/C++, and I've been stuck with this for a while now. Can anyone tell me what I'm doing wrong, or point me in a better direction?
You want to add multiple unsigned char objects to your vector, but push_back only adds one.
So, replace retbuf.push_back(*outbuf); with either:
for (size_t i = 0; i < sizeof(outbuf); ++i) {
retbuf.push_back(outbuf[i]);
}
or
std::copy(outbuf, outbuf+sizeof(outbuf), std::back_inserter(retbuf));
or
retbuf.insert(retbuf.end(), outbuf, outbuf+sizeof(outbuf));
which all do the same thing.
You create your vector with a certain size:
buffer_t retbuf(0x40 * reports);
but push_back increases the size of the vector by adding an element at the end. You should create it empty:
buffer_t retbuf;
Optionally, you could arrange for the vector to have enough space allocated, ready for the elements you're going to add:
retbuf.reserve(0x40 * reports);
This is purely a performance issue, but sometimes it's a significant issue for large vectors, or vectors of types that (unlike unsigned char) are expensive to copy/move when the vector runs out of internal space and has to allocate more.
A note on style: you repeat the literal value 0x40 a few times, and also use sizeof(outbuf). It's often best to define a constant, and use the name throughout:
const int report_size = 0x40;
This is partly in case the number changes in future, but also it's about the readability of your code -- if someone sees 0x40 they may or may not immediately understand why that is the correct value. If someone sees report_size then they don't know what value that actually is until they look it up, but they do know why you're using that value.
The problem is in this line: buffer_t retbuf(0x40 * reports); It means that you create vector with 0x40 * reports elements filled with default value for unsigned char (zero). Then push_back() just adds new elements to the end of vector and doesn't affect existing elements.
You need to rewrite it this way:
buffer_t retbuf; // Empty vector
retbuf.reserve(0x40 * reports); // Preallocate memory for known element count
This way push_back() will work as expected and add elements to empty vector from beginning.
And of course you shall push_back() all elements of outbuf, not only first one (*outbuf).
To push back multiple values use std::vector's function assign. For example:
std::vector<char>vec1;
char array[3] = {'a', 'b', 'c'};
vec1.assign(array, array+3);
I am currently working on a project were I had to do this.
Your vector is of a type unsigned char, which means every element of it is of this type. Your outbuf is an array of unsigned chars.
The push_back() only appends one item to the end of the vector, so push_back(*outbuf) will only add the first element of the outbuf to the vector, not all of them.
To put all the data into the vector, you will need to push_back them one-by-one, or use std::copy.
Note that since outbuf is a char array, then *outbuf will be the first element of the char array because of the array/pointer duality.
I think you probably wanted to do:
typedef vector<string> buffer_t; // alternatively vector<unsigned char*>
...
retbuf.push_back(outbuf);
...
Or
typedef vector<unsigned char> buffer_t;
...
for (size_t i = 0; i < sizeof(outbuf); i++)
retbuf.push_back(outbuf);
...
I have a (void*) buffer that I need to convert to std::vector<unsigned char> before I can pass it on. Unfortunately, my C++ casting skills a little weak. Any suggestions?
You will need the length of the buffer. Once you do, we can do this:
unsigned char *charBuf = (unsigned char*)voidBuf;
/* create a vector by copying out the contents of charBuf */
std::vector<unsigned char> v(charBuf, charBuf + len);
Okay, the comment got me started on why I did not use reinterpret_cast:
In C++, the C-style cast is a convenience function -- it asks the compiler to choose the safest and most portable form of conversion over the set of available cast operators.
The reinterpret_cast is implementation defined and should always be the last thing on your mind (and used when you are necessarily doing a non-portable thing knowingly).
The conversion between (unsigned doesn't change the type) char * and void * is portable (you could actually use static_cast if you are really picky).
The problem with the C-style cast is: the added flexibility can cause heartaches when the pointer type changes.
Note: I agree with the general convention of not casting as much as possible. However, without any source provided, this is the best I could do.
You can't simply cast a void* to a std::vector<unsigned char> because the memory layout of the latter includes other objects, such as the size and the number of bytes currently allocated.
Assuming the buffer is pointed to by buf and its length is n:
vector<unsigned char> vuc(static_cast<char*>(buf), static_cast<char*>(buf) + n);
will create a copy of the buffer that you can safely use.
[EDIT: Added static_cast<char*>, which is needed for pointer arithmetic.]
The only time this would be legitimate is if you had already created a vector, and simply wanted to get it back.
void SomeFunc(void* input);
main() {
std::vector< unsigned char > v;
SomeFunc((void*) &v);
}
SomeFunc(void* input) {
// Now, you could cast that void* into a vector
std::vector< unsigned char >* v_ = (vector<unsigned char>*)input
}
I haven't actually tried to see if this will run, but that's the spirit of it. That said, if you are making this from scratch, you are definitely doing it wrong. This is really bad. The only time this could be even remotely understandable is if you are forced to implement the already defined "SomeFunc()".
using std::vector class for an already allocated buffer is not a solution. A std::vector object manages the memory and deallocates it at destruction time.
A complicated solution might be to write your own allocator, that uses an already allocated buffer, but you have to be very careful on several scenarios, like vector resizing, etc.
If you have that void* buffer bound through some C API functions, then you can forget about conversion to std::vector.
If you need only a copy of that buffer, it can be done like this:
std::vector< unsigned char> cpy(
(unsigned char*)buffer, (unsigned char*)buffer + bufferSize);
where bufferSize is the size in chars of the copied buffer.