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

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.

Related

copy of an array into a vector not happening as expected

I am trying to copy an array to a vector.
int A[1000]; //This array is filled by some function
vector<int> vec;
//some position from which I want to write the contents of the array into vector
int x = some_position;
vec.resize(sizeof(A)+x);
vec.insert(vec.begin()+x, A, A+sizeof(A));
The problem is that every fourth element is not copied correctly. The rest of the elements are copied correctly. i.e vec[x+3] != A[x+3]
for x=0,1,2,3....
First off, you need to check your understanding of sizeof. It returns the number of bytes needed for A as a whole, not the number of items in A, for that you would need sizeof(A)/sizeof(*A).
int A[1000];
vector<int> vec;
int x = 5;
vec.resize(x + sizeof(A) / sizeof(*A));
vec.insert(vec.begin()+x, A, A + sizeof(A) / sizeof(*A));
It's also worth noting that 'insert' may not be what you want. If your objective is to treat the vector like an array and overwrite a 1000 element long section of the vector, then you should use std::copy instead. Insert will resize the array even more, so if the resize will make the vector 1005 elements long, and them you start inserting at position 5, then the final vector will be 2005 elements long, with the contents of A going from 5 - 1004.
You could instead replace the insert line with this:
std::copy(A, A + sizeof(A) / sizeof(*A), vec.begin() + x);
This would overwrite the contents of the vector starting at position 5 and leave the vector sized at 1005.
The better way to copy array to vector:
vec.resize(1000+some_position);//if needed
std::copy(A,A+1000,vec.begin()+some_position);
It seems you believe sizeof() gives number of elements
e.g.
vec.resize(sizeof(A)+x);
but it doesn't. it gives the number of bytes.
the correct resizing should be something along the lines of
vec.resize(sizeof(A)/sizeof(int)+x);
of that follows that
vec.insert(vec.begin()+x, A, A+sizeof(A)/sizeof(int));
although I agree with Sergey that copy() is the better (more elegant) way to do it.
Your use of sizeof is wrong. sizeof is a very primitive operator,
which returns the number of bytes in the shallow image of the object
or type. This is totally useless except for very low level programming.
If you need to deal with C style arrays, there functions std::begin()
and std::end() in C++11; in earlier versions of C++, we just wrote
them ourselves. (I usually also wrote a size() function, which
basically returned the number of elements.) And std::vector works in
number of elements, not number of bytes. So your last two lines of code
should be:
vec.resize( x );
vec.insert( vec.end(), std::begin( A ), std::end( A ) );
At least, that's what I think you're trying to do, based on the
comments: create an std::vector<int> with x elements initialized to
0, followed by the contents of A.
Replace sizeof(A) with sizeof(A) / sizeof(A[0]) and it will work.
And as #Sergey pointed out, vec.resize(); in unnecessary in this case as insert() also resizes the vector.
don't copy an array into a vector. Use C++ to avoid that altogether. Instead of
void fill_array(int*, size_t);
int A[1000];
fill_array(A,1000);
std::vector<int> vec;
my_copy(vec,A);
simply do
std::vector<int> vec;
vec.resize(1000); // or whatever
fill_array(vec.data(),vec.size()); // std::vector::data() is C++11
In C++ (also pre C++11) you would actually do this more like this:
template<typename iterator> fill_data(iterator begin, iterator end);
std::vector<int> vec;
vec.resize(n); // make space (otherwise fill_data cannot fill in anything)
fill_data(vec.begin(), vec.end());
then your fill_data is generic enough to be re-used for any type of container.

C++ assign array of ints to an empty array of ints same size

I am very familiar with Java and this is allowed there. However it looks like it's not with C++. I'm getting an "invalid array assignment" when trying to assign valuesToGrab = updatingValues;.
//these are class attributes
int updatingValues[361] = {0};
int valuesToGrab[361] = {0};
//this is part of a function that is causing an error.
for (unsigned int i=0; i < 10; i++) {
//this fills values with 361 ints, and num_values gets set to 361.
sick_lms.GetSickScan(values,num_values);
//values has 361 ints, but a size of 2882, so I copy all the ints to an array
//of size 361 to "trim" the array.
for(int z = 0; z < num_values; z++){
updatingValues[z] = values[z];
}
//now I want to assign it to valuesToGrab (another program will be
//constantly grabbing this array, and it can't grab it while it's being
//populated above or there will be issues
valuesToGrab = updatingValues; // THROWING ERROR
}
I don't want to have to iterate through updatingValues and add it to valuesToGrab one by one, but if I have to I will. Is there a way I can assign it in one function with C++?
Thanks,
The standard idiom for copying in C++ is
#include <algorithm>
...
std::copy(values, values+num_values, updatingValues);
make sure updatingValues is large enough or you will get overruns and bad things will happen.
That said in C++ we generally use a std::vector for this sort of task.
#include <vector>
...
std::vector<int> updatingValues=values; //calls vectors copy constructor
I vector does everything an array does (including static initalization in C++11), but has a well define interface. with iterators, size, empty, resize, push_back and more.
http://en.cppreference.com/w/cpp/algorithm/copy
http://en.cppreference.com/w/cpp/container/vector
EDIT
It is also worth noting that you can combine vector and arrays.
std::vector<int> vect(my_array, my_array+10);
//or
std::vector<int> another_vector;
...
another_vector.assign(my_array, my_array+10);//delayed population
and visa-versa
std::copy(vect.begin(), vect.end(), my_array); //copy vector into array.
First of all, I don't think this will do what you're looking for because valuesToGrab = updatingValues; will overwrite your valuesToGrab every cycle of the outer loop.
Assuming you did want to do this though, and you didn't want to change to a vector:
std::copy(updatingValues, updatingValues+361, valuesToGrab);
will do it. You can treat a normal array just like a std:: container in any std::algorithm, the pointers count as random access iterators.
Rethink your design though, you shouldn't need to "trim" and you probably don't need to copy.
In C++, the idiomatic container to use in place of arrays is std::vector. With vector or with arrays, you can use the std::copy() function from the <algorithm> header, which is the preferred way of copying containers of any sort in C++. With vector:
std::vector<int> updatingValues, valuesToGrab;
// Ensure the vector has sufficient capacity to accept values.
updatingValues.resize(361);
// Copy values from the array into the vector.
std::copy(values, values + 361, updatingValues.begin());
// Source begin & end; Destination begin.
// Copy one vector to another.
valuesToGrab = updatingValues;
With arrays:
std::copy(valuesToGrab, valuesToGrab + 361, updatingValues);
Again with just arrays, if you are going for more of a C style, you can use the C standard library function memcpy(), from <cstdlib>:
memcpy(valuesToGrab, updatingValues, 361 * sizeof(int));
// Destination; Source; Number of bytes.
With memcpy() (and its cousin, memmove()), you must be careful about the size of the elements you’re copying; if you say 361 instead of 361 * sizeof(int), you’ll copy 361 bytes, not 361 ints’ worth of bytes—a big difference.
Keep in mind that arrays are implemented as pointers in C and C++.
In particular an array on the stack can be visualized as a pointer to a constant location in memory that has the capacity that you requested for the array. This memory is on the stack. When you try valuesToGrab = updatingValues, you could think of this as trying to copy the address of updatingValues to the variable valuesToGrab. This is NOT attempting a deep copy, which you seem to be attempting. However, valuesToGrab points to a constant location in memory and cannot be updated. The standard is a little more specific on this and explicitly forbids the assignment of arrays, which is why you're getting the specific error that you're seeing.
You will need to use a loop or something like std::copy or C's memcpy to copy the values from one array to the other.

Move element in array in order

How to move element in array in order or remove from array?
Example: arr[3,3,2,1]
move(arr[0],arr[sizeof(arr)]);
arr[3,2,1,3];
I wrote function, but is correctly it ?
void remove(int index, char *arr)
{
arr[index]=NULL;
for(int i=index;i<sizeof(arr)-1;i++)
swap(arr[i],arr[i+1]);
}
Well, first off, I'm going to suggest using std::vector instead of an array since you're using C++. It will make this process much simpler. As for your function, I want to cover a few things...
arr[index] = NULL;
If I remember right, NULL is 0, so this is fine. However, I'm assuming you're under the impression that this is a pointer, which it is not. Although you may have a pointer to the array, each individual element of the array is not a pointer. To get this, you would need to pass a char **. The reason this works in this case is because a char is really an int.
sizeof(arr)-1
This will not get you the number of elements of the array. You asked for the size of arr, which is going to return the size of the pointer data type. A better option here would be to iterate through with pointer arithmetic until you reach the end of the data. Remember, a pointer to an array by the end of the day is still just a pointer and does not contain any overhead about the array itself. It just knows which element it is pointing to.
This already exists in the C++ standard library (std::rotate), and the C standard library (memmove)
If you're using C++, (since it comes with a std::swap function, and C can't swap with parameters like that):
void remove(int index, char *arr, int len)
{
if (len<=0)
len = strlen(arr);
std::rotate(arr+index, arr+index+1, arr+len);
arr[len-1] = NULL;
}
Also, in C++, use a std::vector or std::string rather than a naked char* pointer.
If you're using C:
void remove(int index, char *arr, int len)
{
if (len<=0)
len = strlen(arr);
memmove(arr+index, arr+index+1, len-index-1);
arr[len-1] = NULL;
}
If you are using naked char* pointers, always pass a length.
You don't have to NULL the element or swap.
void remove(int index, char *arr)
{
int i;
for(i=index;i<strlen(arr)-1;i++)
arr[i] = arr[i+1];
arr[i] = NULL; // i now points to last, "extra" element
}
The sizeof(arr) when arr is declared as actual array with dimension will give you the size of the array in bytes (actually, C++ does not know bytes, only chars, but lets not get into that right now). The arr[sizeof(arr)] makes no sense: you are telling the compiler to get the element that is at the index numerically equal to the size of array in bytes, which is always out of bounds. BTW, to get the size of array in elements, use: sizeof(arr) / sizeof(arr[0]).
The sizeof(arr) when char *arr will give you the size of the pointer (typically 4 or 8 bytes depending on bitness), regardless of how large the array "beneath" that pointer is.
Even when you fix all that (and couple of other more minor things such as using NULL as integer), you will still be just moving the element to the end of the array, not actually re-moving it.
I suggest you use std::vector and its erase method. If you are doing a lot of removes from the middle (and you can live without random-access), consider using std::list (and its erase) instead. Alternatively, you may also consider std::remove.
Do not swap your elements just shift all right allocated elements one position left in order to overwrite you element. Do not forget to decrease size of your array.
It looks correct, indeed.
You should distinguish between cases when you want to remove an element from the array, or simply move it.
Perhaps it is a good idea to transfer the count (by how much to move) as a parameter, and when it is equal to the array length (or 0, for example) - the element would be deleted.

std::list<char> list_type to (char * data, int lenght)

I have some
std::list<char> list_type
Now I have to supply contents of the list as (char *data, int length). Is there convenient way to present list contents as pointer and length? Does <vector> has such interface?
Thank you in advance.
You can do it with a vector, because its data is stored contiguously:
std::vector<char> vec;
char* data = &vec[0];
int length = static_cast<int>(vec.size());
For list, you have to copy the data to an array. Luckily, that too is fairly easy:
std::list<char> list:
int length = static_cast<int>(list.size());
char* data = new char[length]; // create the output array
std::copy(list.begin(), list.end(), data); // copy the contents of the list to the output array
Of course, you're then left with a dynamically allocated array you have to free again.
You can do this with vector, not with list. A vector is guaranteed to be a contigous chunk of memory so you can say:
char *data = &list_type[0];
std::vector<char>::size_type length = list_type.size();
I don't know about std::list, but std::vector does:
std::vector<char> list_type;
...
foo(&list_type[0], list_type.size())
std::string can do the job too, but you probably already know it.
You cannot do this with a list, as a list saves its data in list nodes. However, you can do this with a vector, which is guaranteed to store its data in a contiguous piece of memory. You can use either &v[0] or &*v.begin() to get a pointer to its first element:
void f(std::list<char>& list)
{
std::vector<char> vec(list.begin(),list.end());
assert(!vec.empty());
c_api_function(&vec[0],vec.size());
// assuming you need the result of the call to replace the list's content
list.assign(vec.begin(),vec.end());
}
Note that the vector will automatically free its memory when the function returns.
There are (at least) two more noteworthy things:
The vector must not be empty. You are not allowed to access v[0] of an empty vector. (Neither are you allowed to dereference v.begin().)
Since dynamic allocation is involved, converting back and forth between std::list and std::vector can be a real performance killer. Consider switching to std::vector altogether.
list is a linked list data structure. There's no way you could do that (theoretically) without conversion.
You'll be able to access (C++0x Draft 23.2.6.3) the backing store of a vector with .data() in C++0x. Currently, your best bet is to treat it as an array by taking the address of the initial element.

C++ How can I iterate till the end of a dynamic array?

suppose I declare a dynamic array like
int *dynArray = new int [1];
which is initialized with an unknown amount of int values at some point.
How would I iterate till the end of my array of unknown size?
Also, if it read a blank space would its corresponding position in the array end up junked?
Copying Input From users post below:
Thing is:
a) I'm not allowed to use STL (means: no )
b) I want to decompose a string into its characters and store them. So far I wanted to use a function like this:
string breakLine (string line){
int lineSize = line.size();
const char *aux;
aux=line.data();
int index=0;
while (index<=lineSize){
mySynonyms[index]=aux[index];
index++;
}
I thought that the array aux would end up junked if there was a large blank space between the two numbers to be stored (apparently not). And I was wondering if there was a way to iterate till an undefined end in this type of array. Thanks for you answers.
You don't: wrap the array into a structure that remembers its length: std::vector.
std::vector v(1);
std::for_each( v.begin(), v.end(), ... );
No portable way of doing this. Either pass the size together with the array, or, better, use a standard container such as std::vector
Short answer is that you can't. If you have a pointer to the first element of an array, you can't know what the size of the array is. Why do you want to use a array in the first place. You would be much better off using a std::vector if your array can change size dynamically, or a boost::Array if it will be a fixed size.
I don't understand your second question.
Your code needs to keep to track of the array, so the size would never be unknown. (Or you would have to use some library with code that does this.)
I don't understand the last part of your quesiton. Could you elaborate?
You explained in your post below that you want to look at the guts of a std::string.
If you are expecting your stirng to be like a c-string (aka doesn't contain NULLs), then use line.c_str() instead of line.data(). This will guarantee that aux points to a null terminates c-style string.
After that you can iterate until aux[index] == '\0';
Otherwise, you can use line.data() and string.length/size to get it's size like in your example.
However, "decomposing a string into its characters" is pretty pointless, a string is an array of characters. Just make of copy of the string and store that. You are allowed to do:
char ch = line[index];
Better yet, use iterators on the original string!
for(std::string::const_iterator it = line.begin(); it != line.end(); ++it) {
const char ch = *it;
// do whatever with ch
}
a) I'm not allowed to use STL (means:
no )
What?? Who's moronic idea was that?
std::vector isn't part of the "STL" (which is a copyrighted product of HP), but is (and has been for nearly a decade) part of the C++ Language Standard.
If you're not allowed to use the STL (for whatever reason), the first thing you want to do is actually to implement your own version of it – at least the parts you need, with the level of customizability you need. For example, it's probably overkill to make your own vector class parametrizable with a custom allocator. But nevertheless do implement your own lightweight vector. Everything else will result in a bad, hardly maintainable solution.
This smells like homework, and the teacher's objective is to give you a feeling of what it takes to implement dynamic arrays. So far you're getting an F.
You need to realize that when you allocate memory like this
int *dynArray = new int [1];
you allocate precisely one integer, not an indefinite number of integers to be expanded by some unidentified magic. Most importantly, you can only say
dynArray[0] = 78;
but you cannot say
dynArray[1] = 8973;
The element at index 1 does not exist, you're stepping into memory that was not reserved for you. This particular violation will result in a crash later on, when you deallocate the array, because the memory where you stored 8973 belongs to the heap management data structures, and you corrupted your heap.
As many other responders mention, you must know how many elements you have in the array at all times. So, you have to do something along the lines of
int arraySize = 1;
int *dynArray = new int [arraySize];
arraySize goes together with the array, and is best combined with dynArray in one C++ object.
Now, before you assign to dynarray[1], you have to re-allocate the array:
if (index > arraySize) {
int newSize = index+1;
int *newArray = new int[newSize]
// don't forget to copy the data from old array to new
memcpy(newarray dynArray, sizeof *newArray * arraySize);
arraySize = newSize;
dynArray = newArray;
}
// now you're ready!
dynArray[index] = value;
Now, if you want to make it a bit more efficient, you allocate more than you need, so you don't have to allocate each time you add an element. I'll leave this as an exercise to the reader.
And after doing all this, you get to submit your homework and you get to appreciate the humble std::vector that does all of this for you, plus a lot more.
Use a vector, which has a vector.size() function that returns an integer and a vector.end() function that returns an iterator.
You could create a simple Vector class that has only the methods you need. I actually had to recreate the Vector class for a class that I took this year, it's not very difficult.
If there's a value that cannot be valid, you can use that as a sentinel, and make sure all of your arrays are terminated with that. Of course, it's error-prone and will cause hard-to-find bugs when you happen to miss doing it once, but that's what we used to do while reading files in FORTRAN (back in the all-caps days, and before END= became standard).
Yes, I'm dating myself.