Reference to a subarray within an array - c++

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.

Related

Understanding syntax of function parameter: vector<vector<int>> A[]

I'm solving a question where a function is defined as following:
vector <int> func(int a, vector<vector<int>> B[]){
// Some stuff
}
I'm confused about why the second parameter is not simply vector<vector<int>> B. Why the extra [] part in the parameter? Can someone clarify the meaning of this?
The vector, B, is populated by a similar code snippet:
vector<vector<int>> B[10];
while(num--){
cin>>u>>v>>w;
vector<int> t1,t2;
t1.push_back(v);
t1.push_back(w);
B[u].push_back(t1);
t2.push_back(u);
t2.push_back(w);
B[v].push_back(t2);
}
Just as int foo(char str[]) is a function that takes a (c-style) array of characters, so int foo(vector<vector<int>> B[]) takes an array of vectors of vectors ... of integers. This means that it's three-dimensional data, requiring 3 indices to access the elements (fundamental data type; in this case, int), like B[i][j][k] = 5. Without the extra [] in the API it'd be two-dimensional data: a vector of vectors.
Note that int foo(char str[]) is equivalent to int foo(char str[5]) which is equivalent to int foo(char * str).
In C we usually add the [] to a function declaration to imply that we expect to receive an array of those elements; while * is often used when we expect at most one element. Likewise, adding the number [5] is basically just a comment to the user of the code that they expect 5 elements, but the compiler won't enforce this. These conventions carry over to C++ when we use these c-style arrays ... which is rare.
With c-style arrays there's either going to be a maximum array size in the comments somewhere; or, more commonly, it's provided as an input. That may be what the first argument of the function is supposed to represent.
I agree with KungPhoo here that this API looks suspiciously bad. I'd expect bugs/bad performance just because the choices seem very amateurish. The c-style array means the function can't know where the end of the c-style array is - but the vectors mean that we give up some of the (niche) benefits of c-style simplicity (especially because they're nested!). It seems to be getting the worst of both worlds. But, perhaps, there may be a very niche justification for the API.
B ist a static array (C-style) of 10 elements [0 .. 9]. It's not safe and this code is a terrible mess.
Better use std::array<std::vector<str::vector<int>>, 10> B; instead to have index checking.

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.

Passing a 3-dimensional variable size array by reference in 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.

How to create variable name with integer appended to the end?

I want to create a for loop that will fill a bunch of arrays with data in c++. Now to save space and in the future once more arrays are added which they will, I have the for loop. Each array for demonstration purposes is called Array# (# being a number) The point of the for loop would be to set a constant with maximum arrays, then cycle through each array filling by appending i to the end of the Array name.
For example in pseudo code:
for (i = 1; i < numberofarrays; i++)
{ fill (Array & i) with ("Array" & i & "-default.txt")}
It is impossible to generate Variable Names by any type of code.
(Meaning it is impossible to generate dynamic variable names on Runtime or on Compiletime)
The best solution possible would be a array of arrays:
int Arrays[][];
Calling Arrays[0] would give you the first array.
If you want to determine the number of arrays during Runtime you need to use pointers!
That would look like that:
(int[])* Arrays = new (int[])[numberofarrays];
Accessing the arrays in the array would work the same!
An alternative would be using the container vector from std.
The code would the look like this:
#include<vector>
// More includes
// Optional
using namespace std;
// Somewhere in your code
vector<vector<int>> Arrays;
You still would acces the elements by using your standard array method (Arrays[15][78] e.g.)
You don't really need the name. You can use an std::vector of arrays. This will not work out of the box, see Correct way to work with vector of arrays
Another approach would be to have an std::map of arrays. You could have the name as the key, if that is what you really want. You will still have to use the same workaround as before to have an array as a value. See Character Array as a value in C++ map for example.

Handling multi-dimensional array lengths in C++

I would like to build a function that takes a multidimensional array and prints it like a grid. I'm having trouble with it because c++ doesn't allow a function to have a multidimensional array argument unless you specify its length. There is a question about it on here, that was answered using vectors. I haven't learned how to use vectors yet, so please don't use them in an answer, or at least provide a good tutorial on them if you do.
Anyway, I was wondering if it's possible to return an array in c++... I started programming with javascript, so the first solution I thought of was to do something like
int gen(int len){
return int arr(int a[][len]){
cout << a[0][0];
};
}
I knew it wouldn't work, tried it, and wasn't surprised when it didn't. Is there a way to do something like this though?
In C++ you can pass array by reference. With making an array a template, it's possible to receive any length in the function. For example,
template<size_t SIZE1>
void print (int (&arr)[SIZE1])
{ ... }
template<size_t SIZE1, size_t SIZE2>
void print (int (&arr)[SIZE1][SIZE2])
{ ... }
template<size_t SIZE1, size_t SIZE2, size_t SIZE3>
void print (int (&arr)[SIZE1][SIZE2][SIZE3])
{ ... }
This pattern will internally create a unique function for every different size of array. It offers ease of use, but may increase the code size.
You have to know the size of the array, there's no way around it. std::vector is the correct way to solve this, and you can find a good reference here. That allows passing only the vector, as it knows its own length and the function can ask it, making it similar to what you're used to from Javascript.
Otherwise, you must pass the size of the array to the function one way or another.
One way is using templates, but that would not work on dynamic arrays (and is a bit wasteful, as it creates a copy of the function per each array size used). The other is just adding an additional parameter to the function, with the size.