Is there any way to re-define an array in c++? - c++

I have the following array in my program:
int foo[] = {1,2,3,4,5};
//Do something with foo, but then there's no use with it afterwards
Since I need a lot more "single-use" arrays just like this, I want to re-define it like the following:
foo[] = {5,2,3}; //Raises an error
Note the array size could vary.
The only solution I've got is to create a new array for each re-definition, but that would be too much storage.
Is there any way of re-defining? Or is there any other solutions?

As the array must be able to vary its size, you could consider using std::vector instead of raw arrays and reassigning the vector whenever you need a new "array":
#include <vector>
#include <cassert>
int main() {
std::vector<int> foo = {1, 2, 3, 4, 5};
assert(foo.size() == 5);
foo = {5, 2, 3}; // <-- reassign
assert(foo.size() == 3);
}
The assignment replaces the vector's contents with those of the initializer list. No additional memory allocation will occur if the vector has enough capacity to store it.

Well, an array is not a first class object, but looks more like the beginning of a memory zone that will contain a sequence of objects. Because of that, the C++ does not allow to directly assign to an array. Full stop (BTW the ancestor C language does not either).
Workarounds:
use a pointer to a dynamic array. Simple but it will require you to initialize the content of each new array. And you are supposed to take care of freeing the array before reusing the pointer - not really the C++ philosophy...
use a vector. Exactly the previous way but nicely encapsulated in the vector class that will take care of allocation management and current size for you
use one single array of the size of the longuest arrays you want to uses and copy the expected data there
In those ways (except for the vector which is much more programmer friendly, you are supposed to keep track of the current used length
But if the reason is to save memory, the simplest and most efficient way is to directly use a pointer to initialized arrays. If you can extract the initialization data at run time, it must be present somewhere since build time, so why not directly use that memory(*)? The only downside I can imagine is that you will have track the length of the pointed array.
There is one notable exception. In some embedded system, initialization data can be stored in read only memory. In that case, you cannot directly use that memory if you need to write in it...

You can always just open & close a new scope for the lifetime of such "temporary" variables:
void bar() {
{
int foo[] = {1, 2, 3, 4, 5};
// Do something with the first foo
}
{
int foo[] = {5, 2, 3};
// Do something with the second foo
}
}

Related

C++ Function Alters Value of Passed Parameter

I have a simple swapping function to take an integer array, and return a new array with swapped values.
int* Node::dataSwap(int *data, int n_index, int swap_index){
printDatt(data);
int *path = data;
int swapped = data[n_index];
int to_swap = data[swap_index];
path[n_index] = to_swap;
path[swap_index] = swapped;
printDatt(data);
return path;
}
However, the reference to the original data is being altered by this function. The output looks something like this (printing the should be the same data to console).
0, 1, 2
3, 4, 5
6, 7, 8
0, 1, 2
3, 4, 8
6, 7, 5
Why is "data" being changed when I am not changing it? Is "path" a reference to the actual mem addr of "data"?
The type of the argument data and the local variable path is int *. You can read this as "pointer to int".
A pointer is a variable holding a memory address. Nothing more, nothing less. Since you set path = data, those two pointers are equal.
In your mind, data is an array. But that's not what the function dataSwap is seeing. To the function dataSwap, its argument data is just a pointer to an int. This int is the first element of your array. You accessed elements of the array using data[n_index]; but that's just a synonym for *(data + n_index).
How to remedy to your problem?
The C way: malloc and memcpy
Since you want to return a new array, you should return a new array. To do this, you should allocate a new region of memory with malloc, and then copy the values of the original array to the new region of memory, using memcpy.
Note that it is impossible to do this using only the current arguments of the function, since none of those arguments indicate the size of the array:
data is a pointer to the first element of the array;
n_index is the index of one of the elements in the array;
swap_index is the index of another element in the array.*
So you should add a fourth element to the function, int size, to specify how many elements are in the array. You can use size as argument to malloc and memcpy, or to write a for loop iterating over the elements of the array.
New problem arising: if you call malloc to allocate new memory, then the user will have to call free to free the memory at some point.
C++ has the cool keyword new whose syntax is somewhat lighter than the syntax of malloc. But this doesn't solve the main problem; if you allocate new memory with the keyword new, then the user will have to free the memory with the keyword delete at some point.
Urgh, so much burden!
But this was the C way. A good rule of thumb in C++ is: never handle arrays manually. The standard library has std::vector for that. There are situations where using new might be the best solution; but in most simple cases, it isn't.
The C++ way: std::vector
Using the class std::vector from the standard library, your code becomes:
#include <vector>
std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
std::vector<int> new_data = data;
int swapped = data[n_index];
int to_swap = data[swap_index];
new_data[n_index] = to_swap;
new_data[swap_index] = swapped;
return (new_data);
}
No malloc, no new, no free and no delete. The class std::vector handles all that internally. You don't need to manually copy the data either; the initialisation new_data = data calls the copy constructor of class std::vector and does that for you.
Avoid using new as much as you can; use a class that handles all the memory internally, like you would expect it in a higher-level language.
Or, even simpler:
The C++ way: std::vector and std::swap
#include <vector>
#include <algorithm>
std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
std::vector<int> new_data = data;
std::swap(new_data[n_index], new_data[swap_index]);
return (new_data);
}
Is "path" a reference to the actual mem addr of "data"?
Yes! In order to create a new array that is a copy of the passed data (only with one pair of values swapped over), then your function would need to create the new array (that is, allocate data for it), copy the passed data into it, then perform the swap. The function would then return the address of that new data, which should be freed later on, when it is no longer needed.
However, in order to do this, you would need to also pass the size of the data array to the function.
One way to do this, using 'old-style' C++, is with the new operator. With the added 'size' parameter, your function would look something like this:
int* Node::dataSwap(int *data, int n_index, int swap_index, int data_size)
{
printDatt(data);
int *path = new int[data_size]; // Create new array...
for (int i = 0; i < data_size; ++i) path[i] = data[i]; // ... and copy data
int swapped = data[n_index];
int to_swap = data[swap_index];
path[n_index] = to_swap;
path[swap_index] = swapped;
printDatt(data);
return path; // At some point later on, your CALLING code would "delete[] path"
}
You are changing the memory at which the pointer path point and that is data. I think try to understand better how the pointers works will help you. :)
Then you can use the swap function from the std library:
std::swap(data[n_index], data[swap_index]);
It will make your code nicer.

Resizing array, does this code influence it badly in any way?

I've seen bunch of tutorials and threads, but no-one does this to resize an array. My question is, whether this affects bad something in my program or is there better way to resize it?
//GOAL:Array to become {1,2,4,5,6,7,8,9}
int size=9;
int array[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 2; i < 8; ++i)
array[i] = array[i + 1];
//ARRAY IS NOW{1, 2, 4, 5, 6, 7, 8, 9, 9}
//GOAL: TO DELETE THAT LAST 9 FROM ARRAY
size=8;
array[size];
//IT SHOULD BE {1,2,4,5,6,7,8,9} now, but does it effect my program in any negative context?
int array[size] declares an array of size elements.
Outside of a declaration, array[size] access element size in array. It does not resize the array. If you do something like that without changing the value of size, it actually tries to access the element after the last element in the array; not a good idea. In this case, since you changed size to be one less than the original, it accesses the last element of the array, which is safe but does not do what you want.
You can not resize an array in C/C++ that is declared on the stack (one allocated on the heap with malloc could be reallocated to a different size, but you'd have trouble copying it as the newly allocated array of the new size is possibly at a completely different memory location; you'd have to save the old one, allocate a new one of the new size, copy the elements you want, and then free the old one.)
If you want something resizeable, you are in C++; use a container (vector, for example, but pick the one that most suits your needs).
And....I just saw arnav-borborah's comment; don't know how I missed that. You can't even declare the array like that, as size is not a compile time constant.
Until size variable is not constexpr, this
int size=9;
int array[size] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
is Variable length array, which is not part of c++ standard, only extension of some compilers.
Also automatic arrays are not resizeable, they have fixed size since declaration until they goes out of scope.
You should use some STL container, like std::array, std::vector.
std::array needs to know size at compile time, so there is the best approach, std::vector, which is easy to use and resizeable.
// #include<vector>
std::vector<int> array { 1,2,3,4,5,6,7,8,9 }; // Uniform initialization
// Remove last element
array.pop_back(); // 'array' has now only 8 elements (1..8)
EDIT
As mentioned in comments, if you want to remove n-th element in vector, you may do
array.erase(array.begin()+n);
and job is done.
Hugely. say if you have a payload of 1GB and you Array.Resize the destination array in chunks of 10k then most of your application CPU and wait states will be resizing that array.
If you pre-allocate the array to 1GB, populating that array will be orders of magnitude faster. This is because every time you use Array.Resize.
The computer needs to move that memory in its entirety to another location in memory just to add the extra length you resized it by.
But of cause if you are dealing with very small arrays. This effect is not noticeable.

C++ array of vectors of pointers initialization

I want to allocate an array of vectors in a function. Every vector should be initiated with a size of 0. Afterwards I want to push pointers to objects T to my vectors. Finally I want have a grid with a list of references in every cell. I am stuck at the initialization of the vectors. It seems that they are not allocated ?
typedef std::vector<T*> GridCell;
GridCell* mGrid;
...
int gridSize = 5;
mGrid = new GridCell[gridSize];
mGrid[gridSize] = { GridCell() }; //runtime error here
This might be possibly duplicated to other posts, but I couldn't find one that solves this issue 100%.
mGrid = new GridCell[gridSize];
This line not only allocates an array, but it default constructs all of the entries too!
mGrid[gridSize]
This is an out of bounds error; as the array has length 5, the only valid indices are 0, 1, 2, 3, 4. Trying to access an element at index 5 is undefined behavior.
vector<GridCell> mGrid(5);
// vector<GridCell> mGrid(5, GridCell()); // Same thing as the line above
This is what you should have done instead. With modern C++, it's pretty rare that you should ever have to use new; there are standard objects that serve most of the purposes people once used new for (e.g. using vector instead of dynamically an array), there are smart pointers for most of the remaining cases, and for the few cases still remaining, you're usually better served by writing your own custom class whose purpose in life is to be a wrapper around whatever you're doing with new.

C++ - How do I put a static array inside my array?

I apologize for the total noob question, but I just cannot find an answer. I googled, searched here, searched C++ array documentation, and some C++ array tutorials.
The question is simple. Why does
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
short pixelarray[3][3] = {{1,1,1},{0,0,0},{-1,-1,-1}};
... //do stuff. Imagine a loop here, and BIG array - I'm just simplifying it for StackOverflow
pixelarray = {{1,0,-1},{1,0,-1},{1,0,-1}};
return 0;
}
result in an error?
1>arraytest.cpp(11): error C2059: syntax error : '{'
How do I put a static array inside my array? I realize I could set each item individually, but there has to be a better way.
Built-in arrays in C++ have their problems, and not being assignable does make them rather inflexible. I'd stick with std::array, a C++11 container that emulates a better style of array, which allows a somewhat similar syntax to what you're looking for:
std::array<int, 3> arr{{1, 2, 3}};
std::array<int, 3>{{4, 5, 6}}.swap(arr);
//now arr is {4, 5, 6}
Here's a full sample. The trick is to use the initializer list on a newly-constructed array and then swap that with yours. I believe that the next C++ update is going to remove the need for the double braces as well, which makes it an even closer match to familiar syntax.
Initializer lists can be used just for initialization :)
Like when you declare your variable:
short pixelarray[3][3] = {{1,1,1},{0,0,0},{-1,-1,-1}}; // this is ok
You have to remove this:
pixelarray = {{1,0,-1},{1,0,-1},{1,0,-1}};
And assign new values manually (i.e. pixelarray[x][y] = or with a memcpy(pixelarray, <some other array>, sizeof(pixelarray)))
If you don't want to assign each individual element manually, you can do this:
short pixelarray2[3][3] = {{1,0,-1},{1,0,-1},{1,0,-1}};
memcpy(pixelarray, pixelarray2, sizeof(pixelarray));
As #Nick points out: initializer lists are not for assignment.
Arrays are not assignable, so the short answer is that you can't do exactly what you're asking for. The most direct way to do something similar enough for most purposes is probably a 2D array class that acts as a wrapper around a std::vector, on the order of the one I posted in a previous answer.
If you insist on staying with C-style arrays, one possibility would be to use a pointer:
int main() {
typedef short array[3];
array pixelarray0[3] = {{1,1,1},{0,0,0},{-1,-1,-1}};
array pixelarray1[3] = {{1,0,-1},{1,0,-1},{1,0,-1}};
array *pixelarray = pixelarray0;
// when needed:
pixelarray = pixelarray1;
}
Taking this question from a straight C context, you can have different constant arrays and just copy them with memcpy:
typedef short TArray[3][3];
const TArray a1 = {{1,1,1},{0,0,0},{-1,-1,-1}};
const TArray a2 = {{1,0,-1},{1,0,-1},{1,0,-1}};
// ...
TArray a;
memcpy( a, a2, sizeof(TArray));
Or you could exploit C99 struct copying, but I'd consider this a dangerous hack because the structure might be padded to be larger than the array, or have a different alignment.
typedef struct {
TArray arr;
} TDummyArray;
// ...
TArray a;
*(TDummyArray*)a = *(TDummyArray*)a2;
Once you have declared your array there is no way to use the assignment operator to reassign the entire content of the array.
So to change the contents or your array after this:
short pixelarray[3][3] = {{1,1,1},{0,0,0},{-1,-1,-1}};
You need to either loop through the array and manually change each value, or you something like std::memcpy to copy your new values over.
But you should really not be using an array in the first place, use some fromthing the std collections library instead like std::array or std::vector. Only use arrays if you have a really really good reason why you can't use a collection.

How do you copy the contents of an array to a std::vector in C++ without looping?

I have an array of values that is passed to my function from a different part of the program that I need to store for later processing. Since I don't know how many times my function will be called before it is time to process the data, I need a dynamic storage structure, so I chose a std::vector. I don't want to have to do the standard loop to push_back all the values individually, it would be nice if I could just copy it all using something similar to memcpy.
There have been many answers here and just about all of them will get the job done.
However there is some misleading advice!
Here are the options:
vector<int> dataVec;
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
// Method 1: Copy the array to the vector using back_inserter.
{
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
dataVec.reserve(dataVec.size() + dataArraySize);
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 3: Memcpy
{
dataVec.resize(dataVec.size() + dataArraySize);
memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}
// Method 4: vector::insert
{
dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}
// Method 5: vector + vector
{
vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}
To cut a long story short Method 4, using vector::insert, is the best for bsruth's scenario.
Here are some gory details:
Method 1 is probably the easiest to understand. Just copy each element from the array and push it into the back of the vector. Alas, it's slow. Because there's a loop (implied with the copy function), each element must be treated individually; no performance improvements can be made based on the fact that we know the array and vectors are contiguous blocks.
Method 2 is a suggested performance improvement to Method 1; just pre-reserve the size of the array before adding it. For large arrays this might help. However the best advice here is never to use reserve unless profiling suggests you may be able to get an improvement (or you need to ensure your iterators are not going to be invalidated). Bjarne agrees. Incidentally, I found that this method performed the slowest most of the time though I'm struggling to comprehensively explain why it was regularly significantly slower than method 1...
Method 3 is the old school solution - throw some C at the problem! Works fine and fast for POD types. In this case resize is required to be called since memcpy works outside the bounds of vector and there is no way to tell a vector that its size has changed. Apart from being an ugly solution (byte copying!) remember that this can only be used for POD types. I would never use this solution.
Method 4 is the best way to go. It's meaning is clear, it's (usually) the fastest and it works for any objects. There is no downside to using this method for this application.
Method 5 is a tweak on Method 4 - copy the array into a vector and then append it. Good option - generally fast-ish and clear.
Finally, you are aware that you can use vectors in place of arrays, right? Even when a function expects c-style arrays you can use vectors:
vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");
If you can construct the vector after you've gotten the array and array size, you can just say:
std::vector<ValueType> vec(a, a + n);
...assuming a is your array and n is the number of elements it contains. Otherwise, std::copy() w/resize() will do the trick.
I'd stay away from memcpy() unless you can be sure that the values are plain-old data (POD) types.
Also, worth noting that none of these really avoids the for loop--it's just a question of whether you have to see it in your code or not. O(n) runtime performance is unavoidable for copying the values.
Finally, note that C-style arrays are perfectly valid containers for most STL algorithms--the raw pointer is equivalent to begin(), and (ptr + n) is equivalent to end().
If all you are doing is replacing the existing data, then you can do this
std::vector<int> data; // evil global :)
void CopyData(int *newData, size_t count)
{
data.assign(newData, newData + count);
}
std::copy is what you're looking for.
Since I can only edit my own answer, I'm going to make a composite answer from the other answers to my question. Thanks to all of you who answered.
Using std::copy, this still iterates in the background, but you don't have to type out the code.
int foo(int* data, int size)
{
static std::vector<int> my_data; //normally a class variable
std::copy(data, data + size, std::back_inserter(my_data));
return 0;
}
Using regular memcpy. This is probably best used for basic data types (i.e. int) but not for more complex arrays of structs or classes.
vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
std::vector<int> myvector (dataArraySize );//target
std::copy ( myints, myints+dataArraySize , myvector.begin() );
//myvector now has 1,2,3,...10 :-)
Yet another answer, since the person said "I don't know how many times my function will be called", you could use the vector insert method like so to append arrays of values to the end of the vector:
vector<int> x;
void AddValues(int* values, size_t size)
{
x.insert(x.end(), values, values+size);
}
I like this way because the implementation of the vector should be able to optimize for the best way to insert the values based on the iterator type and the type itself. You are somewhat replying on the implementation of stl.
If you need to guarantee the fastest speed and you know your type is a POD type then I would recommend the resize method in Thomas's answer:
vector<int> x;
void AddValues(int* values, size_t size)
{
size_t old_size(x.size());
x.resize(old_size + size, 0);
memcpy(&x[old_size], values, size * sizeof(int));
}
avoid the memcpy, I say. No reason to mess with pointer operations unless you really have to. Also, it will only work for POD types (like int) but would fail if you're dealing with types that require construction.
In addition to the methods presented above, you need to make sure you use either std::Vector.reserve(), std::Vector.resize(), or construct the vector to size, to make sure your vector has enough elements in it to hold your data. if not, you will corrupt memory. This is true of either std::copy() or memcpy().
This is the reason to use vector.push_back(), you can't write past the end of the vector.
Assuming you know how big the item in the vector are:
std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));
http://www.cppreference.com/wiki/stl/vector/start