Code executing : How to create a multiple dimensional array manually? - c++

If I manually type this script and call the calculator :
integer array[100];
Then my calculator will create a vector<int> object with the name "array" contains 100 elements.
But C++ code is unique. For example if I type and call :
integer array[100][100];
integer array[100][100][100];
//etc
Then the template vector<int> is illegal.... :(
So annoying! I tried but I could not find the better solution. Could anyone give me some hint?

This answer covers to generally different approaches.
To support arbitrarily nested, dynamically sized arrays (so the depth of the nested arrays is not limited during compile time), you should use something like the following.
The type of a variable in your scripting language should be either:
integer
float
(... other primitive types you want to support ...)
an array of any of these types (including array)
(... other container types such as an associative map if you want to support it ...)
This is typically done using a "variant" type, such as Boost Variant or QVariant in Qt. A variant type is basically a union of a set of types (so it is one of them) plus a type descriptor which tells which type it actually contains.
So an array of any type can be represented, also if this "any type" is an array again. So you can support a dynamic depth of nested arrays.
Note that the "array of any types" should actually be a vector of this variant type. The problem with Boost Variant is that you have to explicitly list the types it can hold as template arguments. This will result in a recursion:
boost::variant<int, float, ..., std::vector<boost::variant<..., ...> > >
^^^^^^^^^^^^^^^^^^^^^^^^
recursion
In Qt there is the type QVariant which can hold basically any type supported by Qt. QVariant is not a template class and thus its type doesn't contain such a recursion. I don't know if there is a comparable boost type, but I doubt it.
If your arrays can't be resized during execution of the script (or if they should be resized, you can allocate a new one and copy the contents), there is a simpler solution. Just store the arrays in a one-dimensional vector, also store the dimensions of the array in your scripting language in another vector. Then you can use an index method like the following.
class ScriptArray {
vector<int> dim;
vector<int> elements;
int getIndex(vector<int> indexList) const {
int multiplicator = 1;
int index = 0;
for (int i = 0; i < dim.size(); ++i) {
index = multiplicator * indexList[i];
multiplicator *= dim[i];
}
return index;
}
};
This is basically a generalization of the following idea. Consider a two-dimensional array (100 x 100 elements) you want to represent as a one-dimensional one (10000 elements). For any index in the original array (x, y) you can map this to a one-dimensional index for your internal array (x + 100 * y). For a three-dimensional array this just contains another multiplication (x + 100 * y + 100*100 * z) and so on...
The problem with this solution and resizing the array is that the elements "move" within the array when the size of a dimension changes (special case: last dimension, as this dimension is the "outermost" one). So either you can live with the fact that the array would be invalid when resized, or you copy the contents in a new array with the new size, or you implement some complicated resize method which carefully inserts spaces / removes some elements in the array at the correct places.

I am assuming that you have created your own language that you want to parse using C++. Your parser knows that you are defining a variable, since it finds the type integer before an identifier. What you then have to do is check if you have to create a normal variable or a multi-dimensional array.
If no brackets ([]) exist -> Normal variable
If brackets exist -> Make a loop to count how many there are. Then allocate nested
vectors. Only the final vector will have elements of type int.
So the easiest way to implement this is to forget about an array and just view it as a special case of a multi-dimensional array with only one bracket.

Related

How to convert between flat and multidimensional arrays without copying data?

I've got some data structured as a multi-dimensional array, i.e. double[][], and I need to pass it to a function that expects a single linear array of double[] along with dimensional metadata for the multi-dimensional representation.
For example, I might have a 3 x 5 multidimensional array, which I need to pass as a 15-element flat array along with height and width parameters so that the function knows it is a 3x5 array rather than a 5x3 array.
The function will then return a flat array and size metadata, which I need to use to convert the data back into a multidimensional type.
I believe the data layout in memory is exactly the same for both the flat and multi-dimensional representations; the only difference is how the indexing operations are performed. So I'd like to do the "conversion" with typecasting rather than copying the array values.
What's the most correct and readable way to typecast between multidimensional and flat arrays of the same total size?
I actually know what the dimensions of the multi-dimensional array will be at compile time. The array sizes aren't dynamic.
The most correct way has been given by #Maxim Egorushkin and #ypnos: double *flat = &multi[0][0];. And it will work fine with any decent compiler. But unfortunately is not valid C++ code and invokes Undefined Bahaviour.
The problem is that for an array double multi[N][M]; (N and M being compile time contant expressions), &multi[0][0] is the address of the first element of an array of size M. So it is legal to do pointer arithmetics only up to M. See this other question of mine for more details.
What's the most correct and readable way to typecast between multidimensional and flat arrays of the same total size?
The address of the first array element coincides with the address of the array. You can pass around the address of the first element, no casting is necessary.
I would assume the most popular way to do it is:
double *flat = &multi[0][0];
This is how it is done in C, and you do operate with simple C arrays.
You could also have a look at std::array in your use case (dimensions known at compile time), but that one is not multi-dimensional, so if you would cascade it, you would lose the contiguous layout.
You can use cast to a reference to an array. This require to use some fancy C++ type syntax but in return it allows to use all features that work on arrays, like for each loop.
#include <iostream>
using namespace std;
int main()
{
static constexpr size_t x = 5, y = 3;
unsigned multiArray[x][y];
for (size_t i = 0; i != x; ++i)
for (size_t j = 0; j != y; ++j)
multiArray[i][j] = i * j;
static constexpr size_t z = x * y;
unsigned (&singleArray)[z] = (unsigned (&)[z])multiArray[0][0];
for (const unsigned value : singleArray)
cout << value << ' ';
cout << endl;
return 0;
}
Take into account that this and other methods basing on casts work only with real multi-dimensional arrays. If it is an array of arrays (like unsigned **multiArray;), it isn't allocated in a continuous block of memory and a cast cannot bypass that.

How to pass dynamic and static 2d arrays as void pointer?

for a project using Tensorflow's C API I have to pass a void pointer (void*) to a method of Tensorflow. In the examples the void* points to a 2d array, which also worked for me. However now I have array dimensions which do not allow me to use the stack, which is why I have to use a dynamic array or a vector.
I managed to create a dynamic array with the same entries like this:
float** normalizedInputs;//
normalizedInputs = new float* [noCellsPatches];
for(int i = 0; i < noCellsPatches; ++i)
{
normalizedInputs[i] = new float[no_input_sizes];
}
for(int i=0;i<noCellsPatches;i++)
{
for(int j=0;j<no_input_sizes;j++)
{
normalizedInputs[i][j]=inVals.at(no_input_sizes*i+j);
////
////
//normalizedInputs[i][j]=(inVals.at(no_input_sizes*i+j)-inputMeanValues.at(j))/inputVarValues.at(j);
}
}
The function call needing the void* looks like this:
TF_Tensor* input_value = TF_NewTensor(TF_FLOAT,in_dims_arr,2,normalizedInputs,num_bytes_in,&Deallocator, 0);
In argument 4 you see the "normalizedInputs" array. When I run my program now, the calculated results are totally wrong. When I go back to the static array they are right again. What do I have to change?
Greets and thanks in advance!
Edit: I also noted that the TF_Tensor* input_value holds totally different values for both cases (for dynamic it has many 0 and nan entries). Is there a way to solve this by using a std::vector<std::vector<float>>?
Respectively: is there any valid way pass a consecutive dynamic 2d data structure to a function as void*?
In argument 4 you see the "normalizedInputs" array. When I run my program now, the calculated results are totally wrong.
The reason this doesn't work is because you are passing the pointers array as data. In this case you would have to use normalizedInputs[0] or the equivalent more explicit expression &normalizedInputs[0][0]. However there is another bigger problem with this code.
Since you are using new inside a loop you won't have contiguous data which TF_NewTensor expects. There are several solutions to this.
If you really need a 2d-array you can get away with two allocations. One for the pointers and one for the data. Then set the pointers into the data array appropriately.
float **normalizedInputs = new float* [noCellsPatches]; // allocate pointers
normalizedInputs[0] = new float [noCellsPatches*no_input_sizes]; // allocate data
// set pointers
for (int i = 1; i < noCellsPatches; ++i) {
normalizedInputs[i] = &normalizedInputs[i-1][no_input_sizes];
}
Then you can use normalizedInputs[i][j] as normal in C++ and the normalizedInputs[0] or &normalizedInputs[0][0] expression for your TF_NewTensor call.
Here is a mechanically simpler solution, just use a flat 1d array.
float * normalizedInputs = new float [noCellsPatches*no_input_sizes];
You access the i,j-th element by normalizedInputs[i*no_input_sizes+j] and you can use it directly in the TF_NewTensor call without worrying about any addresses.
C++ standard does its best to prevent programmers to use raw arrays, specifically multi-dimensional ones.
From your comment, your statically declared array is declared as:
float normalizedInputs[noCellsPatches][no_input_sizes];
If noCellsPatches and no_input_sizes are both compile time constants you have a correct program declaring a true 2D array. If they are not constants, you are declaring a 2D Variable Length Array... which does not exist in C++ standard. Fortunately, gcc allow it as an extension, but not MSVC nor clang.
If you want to declare a dynamic 2D array with non constant rows and columns, and use gcc, you can do that:
int (*arr0)[cols] = (int (*) [cols]) new int [rows*cols];
(the naive int (*arr0)[cols] = new int [rows][cols]; was rejected by my gcc 5.4.0)
It is definitely not correct C++ but is accepted by gcc and does what is expected.
The trick is that we all know that the size of an array of size n in n times the size of one element. A 2D array of rows rows of columnscolumns if then rows times the size of one row, which is columns when measured in underlying elements (here int). So we ask gcc to allocate a 1D array of the size of the 2D array and take enough liberalities with the strict aliasing rule to process it as the 2D array we wanted. As previously said, it violates the strict aliasing rule and use VLA in C++, but gcc accepts it.

create a Dynamic std::array of std::array

My task requires me to create an array of arrays to store some data , where the number of row is fixed and the columns are to be decided at run-time.
If I was using a simple int array then this would've been a simple task but because I have to use std::array , I am lost .
My attempt so far
#include<iostream>
#include<array>
using std::array;
int main(){
array<array<int,1>*,3> x;
for(size_t i=0;i<3;i++)
{
x[i][0]=array<int,3>;
}
}
which leads to the error
array1.cpp:12:29: error: expected '(' for function-style cast or type
construction
x[i][0]=array;
~~~~~~~~~~~~^ 1 error generated.
when using clang++
I have read that an std::array is equivalent to a normal array ,
I know i can use vectors but since i know how many rows i have from the beginning , I feel it to be a waste to use vectors , while I would love the added functionality of std::array when compared to a traditional array. How do I implement this .
std::array<std::vector<int>,3> is the type you want.
std::vector is a dynamicly sized array.
int main(){
std::array<std::vector<int>,3> x;
for(std::size_t i=0;i<3;i++)
{
x[i]=std::vector<int>(22);
}
}
this creates a 3 "major" element array of 22 "minor" size.
Note that column-major and row-major (which is first and which is second) is a matter of convention. So std::vector<std::array<3,int>> is another equally valid interpretation of the requirements.
If you are banned from using std::vector, you will have to figure out an alternative solution, possibly rolling your own. I'd advise against unique_ptr<int[]> (or worse, raw pointers) as they don't store the size of the element.
A std::array< std::array< cannnot be dynamic in either dimension. std::array is fixed size.
My task requires me to create an array of arrays to store some data , where the number of row is fixed and the columns are to be decided at run-time.
It sounds like your task requires using a matrix class. Like boost::numeric::ublas::matrix.
The benefit of using a matrix class is that internally it uses one dynamic array to minimize storage overhead.
If you are coding this as an exercise create your own matrix class. Otherwise use an existing one.

How to convert one-dimensional array into two-dimensional without memory allocating?

I have a filled one-dimensional array double *vals as a class component with sizes Nn[0]*Nn[1]. I need to get 2-dimensional array **w (w[Nn[1]][Nn[0]]) without allocating new memory for it, e.g. i need to represent vals as 2-dimensional array.
Using g++ compiler i can make
double (* w)[Nn[0]] = (double (*)[Nn[0]])val;
But VS compiler or intel compiler don't allow to use non-constant expression as dimension array.
In general, I can just use element in initial vals array converting 2 int indices (i,j) of w[i][j] element into global index and do not declare w at all. But it would be great if it's possible to get 2-dimensional array w on initial memory (with compiling with intel compiler too). So is there any way to do it?
If wals is a class, you can implement your access operator to function as if it were 2D array.
walsdataType walsclass::operator()(int i, int j){return walsdata[i*N+j]};
with walsdata being the class member for storing data and N being the row length. You should do the bound checking as well.

How to Implement a multidimensional array if the dimension is unknown at compile-time?

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.