I am trying to understand some code that passes a multi dimension array to a function. But the prototype of this function intrigues me.
The program creates this "tab" variable:
#define N 8
float tab[N][N];
tab[0][0] = 2; tab[0][1] = 3; tab[0][2] = -1;
tab[1][0] = 3; tab[1][1] = 1; tab[1][2] = -4;
tab[2][0] = 1; tab[2][1] = 2; tab[2][2] = 3;
hello(tab);
And we have this function:
function hello(float mat[][N]) {
I dont understand why the hello function gets the tab variable with an empty [] and then with [N]. What does it change ? I don't understand... Why not tab[][] ?
The code seems to have been made by a good developer so I don't think that the N variable is here for no reason.
If you can explain me this, thanks for your time !
The original code
float tab[N][N];
defines an array of N by N. I'm not going to use row or column because how the array is oriented to the program logic may have no bearing on how the array is represented in memory. Just know that it will be a block of memory N*N long that can be access with mat[0..N-1][0..N-1]. The sizes are known and constant. When you define an array, it must know its size and this size cannot change. If you do not know the size, use a std::vector or a std::vector<std::vector<YOUR TYPE HERE>>
float tab[][];
is illegal because the size of the array is unknown. The compiler has no clue how much storage to allocate to the array and cannot produce a functional (even if flawed) program.
When you pass an array to a function such as
function hello(float mat[][N])
the array decays into a pointer. More info: What is array decaying? Once the array has decayed, the size of the first dimension is lost. To safely use the array you must either already know the size of the array or provide it as another parameter. Example:
function hello(float mat[][N], size_t matLen)
In question, the size is given as N. You know it's N and you can safely call
hello(mat);
without providing any sizing and simply use N inside the function as the bounds. N is not a devious magic number, but it could be given a more descriptive name.
You can also be totally explicit and
function hello(float mat[N][N])
and remove any ambiguity along with the ability to use the function with arrays of size M by N. Sometimes it's a trade-off worth making.
Let me explain a little bit "untechnically", but probably comprehensive:
Think float tab[ROW][COL] as a two dimensional array of floats, where "ROW" stands for the rows, and "COL" stands for the columns, and think that the array is mapped to memory one complete row following the other, i.e.
r0c0,r0c1,r0c2
r1c0,r1c1,r1c2
r2c0,r2c1,r2c2
for ROW=3 and COL=3. Then, if the compiler would have to find out where to write tab[2][1], it would have to take 2 times the size of a row + 1 (where row size is actually the number of columns COL). So for addressing a cell, it is relevant to know the size of the row, whereas within a row one has just to add the column index. Hence, a declaration like tab[][N] is sufficient, as N defines the number of columns - i.e. the size of a row - and lets the compiler address each cell correctly.
Hope it helps somehow.
Related
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.
I create an array of size int arr[50]; but I will insert value in it during compile time , like my solution will insert 10 values in it after performing some function (different amount of values can come) , Now in second part of my program I have to loop through the array like it should iterate <= total values of array like in int arr[50] my program save 10 values , it should iterate to it only 10 times but how I can get that there is only 10 values in that array.
arr[50]=sum;
for (int ut=0; ut<=arr[100].length();ut++)
Though i know ut<=arr[100].length() is wrong , but its just assumption , that function will work if I solve condition in this way.
Edit:
I know we can use vector , but I am just looking that type of thing using array.
Thanks for response
First of all, the array you show is not a "Dynamic Array". It's created on the stack; it's an automatic variable.
For your particular example, you could do something like this:
int arr[50];
// ... some code
int elem_count = sizeof(arr) / sizeof(arr[0]);
In that case, the sizeof(arr) part will return the total size of the array in bytes, and sizeof(arr[0]) would return the size of a single element in bytes.
However, C-style arrays come with their share of problems. I'm not saying never use them, but keep in mind that, for example, they adjust to pointers when passed as function arguments, and the sizeof solution above will give you an answer other than the one you are looking for, because it would return sizeof(int*).
As for actual dynamically allocated arrays (where all what you have is the pointer to that array), declared as follows:
int *arr = new int[50];
// ... do some stuff
delete [] arr;
then sizeof(arr) will also give you the size of an int* in bytes, which is not the size you are looking for.
So, as the comments suggested, if you are looking for a convenient random access container where you want to conveniently and cheaply keep track of the size, use a std::vector, or even a std::array.
UPDATE
To use a std::array to produce equivalent code to that in your question:
std::array<int, 50> arr;
and then use it like a normal array. Keep in mind that doing something like arr[100] will not do any bounds checking, but at least you can obtain the array's size with arr.size().
While passing a 2-Dimensional array we have to specify the the column.
eg:
void funtion1(a[])// works
{
}
void function2(a[][4])//works
{
}
void function3(a[][])//doesn't work
{
}
What could be the possible reasons that the function3 is considered an incorrect definition.
Is there a different way to define function3 so that we can leave both row and column blank.
Reading some replies:
Can you explain how x[n] and x[] are different?. I guess the former represents a specific array position and the latter is unspecified array. More explanation will be deeply appreciated.
You cannot pass a 2D array without specifying the second dimension, since otherwise, parameter "a" will decay to a pointer, the compiler needs to know how long the second dimension is to calculate the offsets (reason is that 2D array is stored as 1D in memory). Therefore, compiler must know size of *a, which requires that the second dimension be given. You can use vector of vectors to replace 2D array.
with void function2(a[][4]) it knows that there are 4 elements in each row. With void function3(a[][]) it doesn't know, so it can't calculate where a[i] should be.
Use a vector, since it's c++
C style arrays don't work the way you think. Think of them as a block of memory, and the dimensions tell the compiler how far to offset from the original address.
int a[] is basically a pointer and every element is an int, which means a[1] is equivalent of *(a + 1), where each 1 is sizeof(int) bytes. There's no limit or end (simplistically speaking) of the a array. You could use a[999999] and the compiler won't care.
int a[][4] is similar, but now the compiler knows that each row is 4*sizeof(int). So a[2][1] is *(a + 2*4 + 1)
int a[][] on the other hand, is an incomplete type, so to the compiler, a[2][1] is *(a + 2*?? + 1), and who know what ?? means.
Don't use int **a, that means an array of pointers, which is most likely what you don't want.
As some have said, with STL, use vectors instead. It's pretty safe to use std::vector<std::vector<int> > a. You'll still be able to get a[2][1].
And while you're at it, use references instead, const std::vector<std::vector<int> > &a. That way, you're not copying the whole array with each function call.
how does compiler calculate address of a[x][y]?
well simply:
address_of_a+(x*SECOND_SIZE+y)
imagine now that you want
a[2][3]
compiler has to computes:
address_of_a+(2*SECOND_SIZE+3)
if compiler doesn't know SECOND_SIZE how it can compute this?
you have to give it to him explicitly. you are using a[2][1], a[100][13] in your code, so compiler has to know how to compute addresses of these objects.
see more here
I am trying to define a class. This is what I have:
enum Tile {
GRASS, DIRT, TREE
};
class Board {
public:
int toShow;
int toStore;
Tile* shown;
Board (int tsh, int tst);
~Board();
};
Board::Board (int tsh, int tst) {
toShow = tsh;
toStore = tst;
shown = new Tile[toStore][toStore]; //ERROR!
}
Board::~Board () {
delete [] shown;
}
However, I get the following error on the indicated line -- Only the first dimension of an allocated array can have dynamic size.
What I want to be able to do is rather then hard code it, pass the parameter toShow to the constructor and create a two-dimensional array which only contains the elements that I want to be shown.
However, my understanding is that when the constructor is called, and shown is initialized, its size will be initialized to the current value of toStore. Then even if toStore changes, the memory has already been allocated to the array shown and therefore the size should not change. However, the compiler doesn't like this.
Is there a genuine misconception in how I'm understanding this? Does anyone have a fix which will do what I want it to without having to hard code in the size of the array?
Use C++'s containers, that's what they're there for.
class Board {
public:
int toShow;
int toStore;
std::vector<std::vector<Tile> > shown;
Board (int tsh, int tst) :
toShow(tsh), toStore(tst),
shown(tst, std::vector<Tile>(tst))
{
};
};
...
Board board(4, 5);
board.shown[1][3] = DIRT;
You can use a one dimensional array. You should know that bi-dimensional arrays are treated as single dimensional arrays and when you want a variable size you can use this pattern. for example :
int arr1[ 3 ][ 4 ] ;
int arr2[ 3 * 4 ] ;
They are the same and their members can be accessed via different notations :
int x = arr1[ 1 ][ 2 ] ;
int x = arr2[ 1 * 4 + 2 ] ;
Of course arr1 can be seen as a 3 rows x 4 cols matrix and 3 cols x 4 rows matrix.
With this type of multi-dimensional arrays you can access them via a single pointer but you have to know about its internal structure. They are one dimensional arrays which they are treated as 2 or 3 dimensional.
Let me tell you about what I did when I needed a 3D array. It might be an overkeill, but it's rather cool and might help, although it's a whole different way of doing what you want.
I needed to represent a 3D box of cells. Only a part of the cells were marked and were of any interest. There were two options to do that. The first one, declare a static 3D array with the largest possible size, and use a portion of it if one or more of the dimensions of the box were smaller than the corresponding dimensions in the static array.
The second way was to allocate and deallocate the array dynamically. It's quite an effort with a 2D array, not to mention 3D.
The array solution defined a 3D array with the cells of interest having a special value. Most of the allocated memory was unnecessary.
I dumped both ways. Instead I turned to STL map.
I define a struct called Cell with 3 member variables, x, y, z which represented coordinates. The constructor Cell(x, y, z) was used to create such a Cell easily.
I defined the operator < upon it to make it orderable. Then I defined a map<Cell, Data>. Adding a marked cell with coordinates x, y, z to the map was done simply by
my_map[Cell(x, y, z)] = my_data;
This way I didn't need to maintain 3D array memory management, and also only the required cells were actually created.
Checking if a call at coordinate x0, y0, z0 exists (or marked) was done by:
map<Cell, Data>::iterator it = my_map.find(Cell(x0, y0, z0));
if (it != my_map.end()) { ...
And referencing the cell's data at coordinat x0, y0, z0 was done by:
my_map[Cell(x0, y0, z0)]...
This methid might seem odd, but it is robust, self managed regarding to memory, and safe - no boundary overrun.
First, if you want to refer to a 2D array, you have to declare a pointer to a pointer:
Tile **shown;
Then, have a look at the error message. It's proper, comprehensible English. It says what the error is. Only the first dimension of an allocated array can have dynamic size. means -- guess what, that only the first dimension of an allocated array can have dynamic size. That's it. If you want your matrix to have multiple dynamic dimensions, use the C-style malloc() to maintain the pointers to pointers, or, which is even better for C++, use vector, made exactly for this purpose.
It's good to understand a little of how memory allocation works in C and C++.
char x[10];
The compiler will allocate ten bytes and remember the starting address, perhaps it's at 0x12 (in real life probably a much larger number.)
x[3] = 'a';
Now the compiler looks up x[3] by taking the starting address of x, which is 0x12, and adding 3*sizeof(char), which brings to 0x15. So x[3] lives at 0x15.
This simple addition-arithmetic is how memory inside an array is accessed. For two dimensional arrays the math is only slightly trickier.
char xy[20][30];
Allocates 600 bytes starting at some place, maybe it's 0x2000. Now accessing
xy[4][3];
Requires some math... xy[0][0], xy[0][1], xy[0][2]... are going to occupy the first 30 bytes. Then xy[1][0], xy[1][1], ... are going to occupy bytes 31 to 60. It's multiplication: xy[a][b] will be located at the address of xy, plus a*20, plus b.
This is only possible if the compiler knows how long the first dimension is - you'll notice the compiler needed to know the number "20" to do this math.
Now function calls. The compiler little cares whether you call
foo(int* x);
or
foo(int[] x);
Because in either case it's an array of bytes, you pass the starting address, and the compiler can do the additional to find the place at which x[3] or whatever lives. But in the case of a two dimensional array, the compiler needs to know that magic number 20 in the above example. So
foo(int[][] xy) {
xy[3][4] = 5; //compiler has NO idea where this lives
//because it doesn't know the row dimension of xy!
}
But if you specify
foo(int[][30] xy)
Compiler knows what to do. For reasons I can't remember it's often considered better practice to pass it as a double pointer, but this is what's going on at the technical level.
I have an C++ SDK that requires a char[][512] as a parameter. I know that this is supposed to be a list of file names and the number of files could vary. For the life of me I cannot figure out how to declare this. I have an array of CStrings and I am trying to copy them over using strcpy_s and then pass them into the SDK. Any idea on how to do this?
This declaration has a special meaning when used to declare parameter of a function. Within the parameter list it is equivalent to char[100][512], char[123][512], char[3][512] (you get the idea - the first size can be just anything, it is simply ignored) and also to char (*)[512]. Effectively, it will accept as an argument a 2D array of chars with flexible (arbitrary) first size.
The array that you will actually pass to this function should be declared with a concrete first size, for example
char names[3][512] = { "abc", "cde", "fgh" };
if you know the first size at compile time, of course.
If the first size is only known at run time (say, n), you'll have to allocate the array dynamically
char (*names)[512] = new char[n][512];
// Now fill it with names
or, more elegantly, with a typedef
typedef char TName[512];
TName* names = new TName[n];
// Now fill it with names
I expect that the SDK function you are talking about also asks you to pass the first size of the name array as another parameter.
It means 2D array of char. The number of rows could vary, and it should/may be specified in another parameter. C/C++ compilers need to know the number columns when a 2D arrays is passed ,So they can build the mapping function. Simply because arrays decay to pointers when they are passed as parameters, size information is lost. For example:
void fun(char matrix[][512], int rows);
...
char matrix[100][512];
...
fun(matrix, 100);
The mapping function that the compiler construct for a 2D array is similar to:
// arrays in C/C++ are stored in Row-Major Order
matrix[i][j] == matrix[i*numberOfColumns + j]
As you can see, when a 2D array is passed and the size information is lost, we need only the number of columns to index any element in this array.
Here is a way to convert an argv-style array of filenames into the form your SDK needs.
typedef char Char512[512];
Char512 * convert(const char *names[], int n)
{
Char512 * arr;
arr = new char[n][512];
for (int i = 0; i < n; n++)
::strncpy(arr[i], names[i], 512);
return arr;
}
When in doubt, use a typedef.
Just a reminder, if you new[] something, you must delete[] (not delete) it sometime.