Is it possible in c++ to create a type of variable that can hold an array with any dimensions? I mean a variable that can store a 1, 2, 3 ... dimensional array.
I guess that it can be made by templates but I could not figure it out how. I would really appreciate if anyone could help.
It sounds like you want to "create a function that can multiply arrays" that will be used "for a lot of different dimensions."
I would deal with this just like I would deal with a vector output operator: use templates with recursion!
If I wanted to make a function to sum all of the numbers in two vector's when I add them, I could do:
template <typename T>
int operator+(std::vector<T> v1, std::vector<T> v2) {
if(v1.size() != v2.size()) { throw; } //for simplicity
int sum = 0;
for(size_t x = 0; x < v1.size(); x++) {
sum += v1.at(x) + v2.at(x);
}
return sum;
}
Note that the magic here is in the line
sum += v1.at(x) + v2.at(x);
If v1.at(x) and v2.at(x) are std::vector's, we'll just recursively call this function again. But if they're int's, we'll add them into sum and move on.
You can see this in action here: ideone
You could do something similar for your array multiplication. Break the problem down into smaller pieces so you can use recursion and let the templates handle the rest!
Do you ever try dynamic memory? In the case below, it creates a two-dimensional array.
http://www.cplusplus.com/doc/tutorial/dynamic/
If you want to have a three-dimensional array, maybe you can try to define a two-dimensional array in step two of the above example.
For four-dimensional array, third-dimensional array in step 2.
Or, you can keep using pointer.
Related
I'm mostly just documenting this question as someone may stumble upon it, and may find it useful. And also, I'm very curios with, how does std::swap works on a 2D array like: Arr[10][10].
My question arised because as to my understanding an array like this is just a 1D array with some reindexing.
For reference:
How are 2-Dimensional Arrays stored in memory?
int main()
{
const int x = 10;
const int y = 10;
int Arr[y][x];
// fill the array with some elements...
for (int i = 0; i < x*y; i++)
{
Arr[i / y][i % x] = i;
}
// swap 'row 5 & 2'
// ??? how does swap know how many elements to swap?
// if it is in fact stored in a 1D array, just the
// compiler will reindex it for us
std::swap(Arr[5], Arr[2]);
return 0;
}
I could understand swapping two 'rows' if our data type is, say a pointer to a pointer like int** Arr2D then swap with std::swap(Arr2D[2], Arr2D[5]) as we do not need to know the length here, we just need to swap the two pointers, pointing to '1D arrays'.
But how does std::swap work with Arr[y][x]?
Is it using a loop maybe, to swap all elements within x length?
std::swap has an overload for arrays that effectively swaps each two elements, again, using std::swap.
As for the size information, it is embedded within the array type (Arr[i] is int[x]), so the compiler knows to deduce T2 as int and N as 10.
OT: Why aren't variable-length arrays part of the C++ standard? (but this particular case is OK)
I try to write code for this kind of problem like below;
this is part of code and I already define the function.
I want in this loop M[i][j] calculate based on function and allocate to this cell
But I have this error "Expression must have a constant value"
Can anyone help me how I have to write this kind of code.
for (i=0;i=2;i++){
for (j=0;i=2;j++){
double M[i][j];
M[i][j] = function(n,m);
}
}
Thanks
Okay. Let's begin:
1) declaring the array
double M[i][j]; is not declaring an array. In C/C++, the way to do declare a static array would be:
double M[MAX1][MAX2]; //where MAX1 and MAX2 are some constant, predefined values.
There is something called variable-length array, but for now, let's say array lengths in C/C++ must be constants.
To conclude:
int max = 100;
[...]
double Array[max]; ---- WRONG
#define MAX 100
[...]
double Array[MAX]; ---- RIGHT
Same thing applies for multidimensional arrays.
Also, you should do this before the for loops - declaring an array in every iteration makes no sense.
2) assigning values
int n=5, m=5; //for example
for(int i=0;i<n;++i)
for(int j=0;j<m;++j)
{
M[i][j]=someFunction(n,m);
}
This will assign the value of function(n,m) to every element of your nxm array.
I guess this is what you had in mind.
You might want to read a good C/C++ book. These are really basic things. :)
You need to declare M[][] outside of that loop it seems.
double M[2][2];
for (i=0;i=2;i++)
{
for (j=0;i=2;j++)
{
M[i][j] = function(n,m);
}
}
Brackets added for clarity.
Does the function modify m and n? If not, then at the moment you'll populate every item in the array with the same value.
So I'm trying to create an n-dimensional array structure for use in a maze generating program.
I've simplified my problem (for the purposes of trying to get the theory figured out before making it templatized and adding all the necessary helper functions)
So my problem currently boils down to wanting to make an ArbitraryArray class that takes in an argument to its constructor specifying the number of dimensions. Each dimension will have length = 5. (for now)
This is what I have so far:
class ArbitraryArray{
public:
int array[5];
ArbitraryArray*subArray;
ArbitraryArray(){}
ArbitraryArray(int depth){
if (depth == 2) subArray = new ArbitraryArray[5];
else if (depth > 2) for (int i = 0; i < 5; i++) subArray = new ArbitraryArray(depth - 1);
}
};
And I'd create a 2 dimensional object like so:
ArbitraryArray testArray(2);
Or a 3 dimensional object like so:
ArbitraryArray testArray(3);
Problem is, when I tested it for depth = 3 and then tried to set an integer value, via:
testArray.subArray[3].subArray[4].array[4] = 7;
I received a runtime error, leading me to believe that I'm doing something wrong in how I allocate these objects dynamically.
Also, I included an empty default constructor since that gets called by lines like:
subArray = new ArbitraryArray[5];
I'm aware this may not be the best way to go about creating an arbitrary dimensional array data structure, but I'd really like to figure out why this implementation is not working before potentially looking for better methods.
Also I am aware I shouldn't have a line like:
int array[5];
And that it should be a pointer instead so that there isn't a ton of wasted memory allocation for all the levels of the array above the bottom dimension. And I intend to modify it to that after I get this basic idea working.
How about using std::vector for allocating the correct amount of blank memory, which would be
sizeof(T) * dim1 * dim2 * dim3 * ...
Then write a helper class which takes care of the indexing, i.e., it will compute i from given (x,y,z,...), whatever many dimensions you might have.
The beauty of this approach, IMHO, lies in not having to fiddle with pointers, and the helper class simply implements an indexing scheme of your preference (row major or column major).
EDIT
When using std::valarray, things may become easier, as you can use std::slice and/or std::gslice to calculate your indexing for you.
Haven't compiled anything, just visual inspection. What about this:
template<int array_length>
class ArbitraryArray{
public:
int array[array_length];
ArbitraryArray ** subArray;
ArbitraryArray(){}
ArbitraryArray(int depth){
if (depth == 1)
subArray = 0;
else {
subArray = new ArbitraryArray*[array_length];
for (int i = 0; i < array_length; i++)
subArray[i] = new ArbitraryArray(depth - 1);
}
}
};
Well, for once, if depth is greater than 2, you create five ArbitraryArrays, but you save all their pointers in one SubArray pointer. SubArray needs to be an array of pointers to ArbitraryArrays, try ArbitraryArray *subArray[5]; and for (int i = 0; i < 5; i++) subArray[i] = new ArbitraryArray(depth - 1) and see what happens.
In your example you are creating an array that is all over the place in memory instead of one array that is stored in a continuous block of memory. This could cause some issues depending on you handle the memory. e.g. using memcpy on it will never work.
I think a little more flexible approach would be create one large array and instead have an index into the array based on the number of dimensions
int n = static_cast<int>(pow( 5.0, static_cast<double>(depth) ));
Type* a = new Type[ n ];
i.e. since you base your array size on 5, a 2-dim size would be 5x5 and a 3-dim 5x5x5
to access an element in the array say a[2,2,3] (0-based) it could be calculated as
a[2*5*5 + 2*5 + 3]
Just use the Boost multi_array class. It is very flexible, efficient and can perform bounds checking.
Boost Multi-Array
I have a for-loop that needs to incrementally add columns to a matrix. The size of the rows is known before entering the for-loop, but the size of the columns varies depending on some condition. Following code illustrates the situation:
N = getFeatureVectorSize();
float **fmat; // N rows, dynamic number of cols
for(size_t i = 0; i < getNoObjects(); i++)
{
if(Object[i] == TARGET_OBJECT)
{
float *fv = new float[N];
getObjectFeatureVector(fv);
// How to add fv to fmat?
}
}
Edit 1 This is how I temporary solved my problem:
N = getFeatureVectorSize();
float *fv = new float[N];
float *fmat = NULL;
int col_counter = 0;
for(size_t i = 0; i < getNoObjects(); i++)
{
if(Object[i] == TARGET_OBJECT)
{
getObjectFeatureVector(fv);
fmat = (float *) realloc(fmat, (col_counter+1)*N*sizeof(float));
for(int r=0; r<N; r++) fmat[col_counter*N+r] = fv[r];
col_counter++;
}
}
delete [] fv;
free(fmat);
However, I'm still looking for a way to incrementally allocate memory of a two-dimensional array in C/C++.
To answer your original question
// How to add fv to fmat?
When you use float **fmat you are declaring a pointer to [an array of] pointers. Therefore you have to allocate (and free!) that array before you can use it. Think of it as the row pointer holder:
float **fmat = new float*[N];
Then in your loop you simply do
fmat[i] = fv;
However I suggest you look at the std::vector approach since it won't be significantly slower and will spare you from all those new and delete.
better - use boost::MultiArray as in the top answer here :
How do I best handle dynamic multi-dimensional arrays in C/C++?
trying to dynamically allocate your own matrix type is pain you do not need.
Alternatively - as a low-tech, quick and dirty solution, use a vector of vectors, like this :
C++ vector of vectors
If you want to do this without fancy data structures, you should declare fmat as an array of size N of pointers. For each column, you'll probably have to just guess at a reasonable size to start with. Dynamically allocate an array of that size of floats, and set the appropriate element of fmat to point at that array. If you run out of space (as in, there are more floats to be added to that column), try allocating a new array of twice the previous size. Change the appropriate element of fmat to point to the new array and deallocate the old one.
This technique is a bit ugly and can cause many allocations/deallocations if your predictions aren't good, but I've used it before. If you need dynamic array expansion without using someone else's data structures, this is about as good as you can get.
To elaborate the std::vector approach, this is how it would look like:
// initialize
N = getFeatureVectorSize();
vector<vector<float>> fmat(N);
Now the loop looks the same, you access the rows by saying fmat[i], however there is no pointer to a float. You simply call fmat[i].resize(row_len) to set the size and then assign to it using fmat[i][z] = 1.23.
In your solution I suggest you make getObjectFeatureVector return a vector<float>, so you can just say fmat[i] = getObjectFeatureVector();. Thanks to the C++11 move constructors this will be just as fast as assigning the pointers. Also this solution will solve the problem of getObjectFeatureVector not knowing the size of the array.
Edit: As I understand you don't know the number of columns. No problem:
deque<vector<float>> fmat();
Given this function:
std::vector<float> getObjectFeatureVector();
This is how you add another column:
fmat.push_back(getObjectFeatureVector());
The number of columns is fmat.size() and the number of rows in a column is fmat[i].size().
I want to implement a function that gets as a parameter a dimension "n" of an array of integers. This function also gets values "k_1, k_2, ..., k_n" defining the size of the array. Then this function will fill this n-dimensional array.
How do I implement this efficiently with C++?
For example for n = 3 I would use
vector < vector < vector < int > > > array;
But I don't know the dimension at compile time.
Use a one-dimensional array, and fake the other dimensions using multiplication of offsets for indexing, and you can pass the dimension sizes in by vector, i.e.
std::vector<int> create_md_array(const std::vector<int> & dimensions)
{
int size = std::accumulate(dimensions.begin(), dimensions.end(), 1, std::multiplies<int>());
return std::vector<int>(size);
}
You have a couple of choices. You can implement it yourself, basically multiplying the coordinates by the sizes to linearize the multi-dimensional address, and just have a simple std::vector<whatever> to hold the data.
Alternatively, you could use std::valarray and friends to accomplish the same. It has a set of classes that are specifically intended for the kind of situation you describe -- but they're used so rarely that almost nobody understands them. Writing the code yourself stands a good chance of being easier for most people to read and understand.