Passing a 3-dimensional variable size array by reference in C++ - c++

I've been working off of Passing a 2D array to a C++ function , as well as a few other similar articles. However, I'm running into a problem wherein the array I'm creating has two dimensions of variable size.
The initialization looks like:
int** mulePosition;
mulePosition = new int *[boardSize][boardSize][2];
The function looks like:
int moveMule (int boardSize, int ***mulePosition)
And the references look like
moveMule (boardSize, mulePosition)
Boardsize is defined at the beginning of the function, but may change per execution.
The array, properly sized, would be int [boardSize][boardSize][2].

Either use a plain '3-dimensional' array via
int* mulePosition = new int[boardsize*boardsize*2];
and address its elements calculating the offset from the beginning: mulePosition[a][b][c] is mulePosition[boardSize*2*a + 2*b + c],
or use array of arrays of arrays (which would correspond to your int*** declaration) or better (and simpler) vector of vectors of vectors, although the initialization would be a little more complex (you would need to initialize every array/vector).

Either use a std::vector<std::vector<int>> if boardSize is not a const or std::array<std::array<boardSize>, boardSize> (see Multidimensional std::array for how to initialize the std::array).
That being said, it looks like a good idea to hide this in a class Board which provides a nice interface.

Related

Reference to a subarray within an array

I was trying to figure out how can I create sub arrays from within a larger array and got a piece of code here and started using it.
I created an array of ints
int arr[10];
for(int h=0;h<10;h++)
{
arr[h]=20+h;
}
Now say I want a sub-array (of 4 ints) within the same larger array
int (&arrOnly4Elements)[4]=(int (&)[4])(*arr);
It works well and does what I want.
While I understand references and that they point to actual objects, What I am not able to understand how the above code works.
why do we need the braces to surround &arrOnly4Elements
Also, can anyone explain me the RHS (int (&)[4])(*arr); in detail step by step manner.
cdecl.org translates it for you:
int (&arrrOnly4Elements)[4]: declare arrrOnly4Elements as reference to array 4 of int
int &arrrOnly4Elements[4]: declare arrrOnly4Elements as array 4 of reference to int
As NathanOliver pointed out, C++20 introduces std::span. You should take a look at it (also compare this SO question). A std::span is a templated view into an array/contiguous sequence of objects. It consists of a pointer and a size. It makes accessing arrays and sub arrays convenient (allows range based for) and safe (keeps track of the size).
int arr[10];
std::span<int> arr_span = arr;
std::span<int,4> arr_subspan1 = arr_span.first<4>();
std::span<int> arr_subspan2 = arr_span.first(4);
If you cannot yet switch to C++20 you might consider checking GSL which provides a gsl::span which was lately aligned to match std::span.

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.

Arrays of pointer to matrices initialized with arrays

I want to cycle between different matrices using an array of pointer to matrices.I want those matrices' rows initialized using array variables. For different reasons, I can't create a new class.
More specifically I want somethng like that:
First point
#define SIZE size-value
int row1MatrixM [SIZE]= {1,2,3,4,5,1,2,3,4,5};
int row2MatrixM [SIZE] = {2,4,5,7,8,9,10,11,12};
...
Then:
matrixM= {row1MatrixM, row2MatrixM, row3MatrixM .... };
But the complier says I can't initialize a matrix this way.
Now I have:
matrixM, matrixY, matrixX, matrixZ, etc.
Then I would like to access them using pointers, so I would need an array of pointers (a pointer to M, one to Y, etc.)
So I tried to write something like that:
#define NUMBER_OF_MATRICES number-of-matrices-value
int[SIZE][SIZE]* arrayOfPointersToMatrices[NUMBER_OF_MATRICES] = {&matrixM,&matrixY,&matrixX, &matrixZ};
I tried different combinations of [] and ** but no one seems working. I was looking for a type that would allow me to access to the array of pointers (3D array) with brackets:
arrayOfPointersToMatrices[x][y][z]
To get your code working:
Declare the arrays like:
int row1 [NUM_COLS]= {1,2,3,4,5,1,2,3,4,5};
int row2 [NUM_COLS] = {2,4,5,7,8,9,10,11,12};
Declare the 2d matrices like:
int *matrix2d1[NUM_ROWS] = {row1, row2};
int *matrix2d2[NUM_ROWS] = {row3, row4};
Declare the 3d matrices like:
int **matrix3d[NUM_MATRICES] = {matrix2d1, matrix2d2};
An alternative (the "right" way)
I would highly highly highly suggest using vectors. They're baked into the C++ language and infinitely easier than all this array/pointer work.

Trouble with initializing multidimensional array

We usually initialize a 2D array like this:
int a[2][3] = {{2,3,4},{5,6,7}};
I need to initialize the 2D array like this:
int a[2][3];
a[0] = {2,3,4};
a[1] = {5,6,7};
i.e. I want initialize it array by array. Why does this method fail? What should I do? Or can I define a as array of array?
The idea of an array is to keep all the data in memory contiguous, this would not be achieved with the approach you are using, I would recommend using a C style memory management with RAW memory for a low level fast, thigh and possibly dangerous solution, or change to a different data container like the vector (or others) where you can add elements similar to what you want and the memory will still be contagious like the simple array. Although depending on the size of your problem it might be an overkill to use a vector.

2D array vs array of arrays

What is the difference between a 2D array and an array of arrays?
I have read comments, such as #Dave's, that seem to differentiate between the two.
This breaks if he's using 2d arrays, or pointer-to-array types, rather than an array of arrays. – Dave
I always thought that both referred to:
int arr_arr[][];
EDIT: #FutureReader, you may wish to see How do I use arrays in C++?
There are four different concepts here.
The two-dimensional array: int arr[][]. It cannot be resized in any direction, and is contiguous. Indexing it is the same as ((int*)arr)[y*w + x]. Must be allocated statically.
The pointer-to array: int (*arr)[]. It can be resized only to add more rows, and is contiguous. Indexing it is the same as ((int*)arr)[y*w + x]. Must be allocated dynamically, but can be freed free(x);
The pointer-to-pointer: int **arr. It can be resized in any direction, and isn't necessarily square. Usually allocated dynamically, not necessarily contiguous, and freeing is dependent on its construction. Indexing is the same as *(*(arr+y)+x).
The array-of-pointers: int *arr[]. It can be resized only to add more columns, and isn't necessarily square. Resizing and freeing also depends on construction. Indexing is the same as *(*(arr+y)+x).
Every one of these can be used arr[y][x], leading to the confusion.
A 2 dimensional array is by definition an array of arrays.
What Dave was saying is that in that context, there are different semantics between the definition of a 2D array like this:
int x[][];
this:
int *x[];
or this:
int **x;
The answer here is a little more subtle.
An array of arrays is defined as such:
int array2[][];
The pointer-to-array types are defined as:
int (*array2)[];
The array-of-pointer types are defined as:
int* array2[];
The compiler treats both of these a little differently, and indeed there is one more option:
int** array2;
A lot of people are taught that these three are identical, but if you know more about compilers you will surely know that difference is small, but it is there. A lot of programs will run if you substitute one for another, but at the compiler and ASM level things are NOT the same. A textbook on C compilers should provide a much more in depth answer.
Also, if one is interested in the implementation of a 2D array there are multiple methods that vary in efficiency, depending on the situation. You can map a 2D array to a 1D array, which ensures spacial locality when dealing with linearized data. You can use the array of arrays if you want the ease of programming, and if you need to manipulate the rows/columns separately. There are certain blocked types and other fancy designs that are cache-smart, but rarely do you need to know the implementation if you the user.
Hope I helped!
The following is a 2D array that can be called an array of arrays:
int AoA[10][10];
The following is a pointer to a pointer that has been set up to function as a 2D array:
int **P2P = malloc(10 * sizeof *P2P);
if(!P2P) exit(1);
for(size_t i = 0; i < 10; i++)
{
P2P[i] = malloc(10 * sizeof **P2P);
if(!P2P[i])
{
for(; i > 0; i--)
free(P2P[i - 1]);
free(P2P);
}
}
Both can be accessed via AoA[x][y] or P2P[x][y], but the two are incompatible. In particular, P2P = AoA is something that newbies sometimes expect to work, but will not - P2P expects to point to pointers, but when AoA decays into a pointer, it is a pointer to an array, specifically int (*)[10], which is not the int ** that P2P is supposed to be.
2d array can include this:
int x[width * height]; // access: x[x + y * width];
From Wikipedia:
For a two-dimensional array, the element with indices i,j would have
address B + c · i + d · j, where the coefficients c and d are the row
and column address increments, respectively.