Why do we need a measuring range of higher sizes in a multidimensional array?

According to the message

Passing a 2D array to a C ++ function

int array[10][10]; void passFunc(int a[][10]) // <---Notice 10 here { // ... } passFunc(array); 

Why is this higher size required from the internal point of the compiler.

+5
source share
6 answers

Alternative explanation (to matrix decay to pointer):

Let's say we have a one-dimensional array, and we use it as follows:

 int array[10]; int i = array[3]; 

The compiler should know where to find array[3] . He knows that he needs to skip 3 int before he can get to the item array[3] . So it works.

But if we have a two-dimensional array,

 int array[2][5]; int i = array[1][1]; 

To get i here, how many int do the compiler need to skip? He needs to skip the whole line, plus one. Skipping one is easy, since we know the size of one int . But we also need to know the row size in the & mdash array, and the row size is determined by the size * of the number of columns in the row. This is one way to look at it, which explains why you need the last dimension.

Let’s make it a little brain titration, taking it one size further,

 int array[2][2][2]; int i = array[1][1][1]; 

and call the dimensions X, Y, Z.

Here we can say that we have a finite three-dimensional space int s. The unit, of course, has a size of 1 int . The number of lines is determined by Y, the number of planes is determined by Z. This leaves X as the base unit, the size of which is int , as we said. The combination of these three gives a "point".

To be able to get to any point in this three-dimensional space, we need to know where each dimension "stops" and the next begins. Therefore, we need:

  • Unit Size ( int ) to move to size X
  • The size of each plane (Y) to cross the dimension of Y
  • The number of planes to cross the size Z

So again, X is already provided to us, because we use int . But we do not know the size of each aircraft, and we do not know how many aircraft there are. Therefore, we need to specify everything except the first dimension. And this is a general rule.

It also explains why this problem offers a slightly more detailed explanation than just decaying a pointer, because as soon as you move on to more than two dimensions, you still need to know how it works. In other words, you need the total size (product sizes) so that it does not overflow, and you need the size of each size to be able to use sequential indexes [] .

+4
source

Arrays in C / C ++ are a type, but not an object of the first class, and they "decay" into a pointer to the first element when passed to functions.

An int[10][10] is an array of 10 int[10] arrays ... function declarations:

 void foo(int x[][10]); typedef int IntArray10[10]; void bar(IntArray10 *x); 

identical to the compiler.

When passing a 2d array to a function, you pass a pointer to the first element (and the first dimension is ignored), but the element itself is an array, and the compiler must know its size.

+3
source

Unlike what you think from "[]" in the parameter int a[][10] , the function does not accept a two-dimensional array, and a pointer to a one-dimensional array - its prototype is equivalent

 void passFunc(int (*a)[10]) 

array can decay to a pointer to its first element, like all arrays.
This pointer, as usual, is &array[0] , in which case it is a pointer to an array with ten int - a int (*)[10] .

So, this does not mean that you need to specify a "higher dimension", it is a parameter, a pointer to an array of ten elements, and not a two-dimensional array at all.

(You cannot have a pointer to an array of indefinite size, because the compiler must know where a[1] is relative to a[0] , that is, it must know sizeof(*a) .)

+3
source

This is required because in C there is no concept of a multidimensional array.
We can define an array of everything, even another array. The latter can be considered as a multidimensional array.
Now consider a two-dimensional array as:

 int arrray[5][4]; 

This should be interpreted as an array of 5 elements, each of which is an array of 4 int .
The memory layout is consistent: first 4 elements of the first array, then the second, etc. Up to the 5th array of 4 elements.
To access the 2nd element of the 3rd array[2][1] compiler must skip the first 2 arrays , but for this you need to know how many elements to skip .
That is, mathematically, the address of the second element of the 3rd array:

 //pElement2Array3 points the 2nd element of the 3rd array. //Note that 4 is the number of elements of the base dimension int *pElement2Array3 = &array[0] + (2 * 4) + 1; 

(Note: the term (2 * 4) + 1 not multiplied by sizeof(int) because it is done automatically using pointer arithmetic.)
The above math is automatically performed by the compiler when using the addressing array[2][1] , but for its execution the compiler must know how many elements are in the base array (this may be an array of array arrays ...) .

0
source

Simply put, because multidimensional arrays "grow" from right to left. Think of it this way:

int arr [a]; is an array of integers a .

int arr [b][a] - an array of arrays b integers a .

And so on.

As for why you can omit the left-most dimension when passing an array to a function, this is due to "array decay." 6.7.6.3/7 says:

Declaring a parameter as a `` type array must be adjusted to a '' Qualified type pointer

That is, if you declare a function parameter as int param[10] or int param[] , it is instantly / invisibly replaced by the compiler with a pointer to int: int* param , which points to the first element of the array. The array itself remains allocated by the caller.

It works in such a way as to prevent passing arrays to functions by value, which would be very inefficient and in most cases make no sense.

Now for the case of multidimensional arrays, the same rule applies above. Therefore, if you have int param[10][10] , it splits into a pointer to the first element. The first element is an array of 10 integers, so you get a pointer to an array of 10 integers: int (*param)[10] .

The same thing happens if you have int param[][10] , you still get int (*param)[10] . Thus, the leftmost dimension can be anything - it does not matter, because it is ignored.

But other sizes are required, following the leftmost ones, otherwise the compiler would not know what type of pointer would depend on the array. Outside of the special case of function declarations, there is no such thing as int(*param)[] , which would mean "an array pointer to an array of unknown size."

0
source

As the function parameter int a[][10] equivalent to int (*a)[10] , it means: a is a pointer to an array of 10 int . In this case, it is not a 2D array.

If a higher dimension is left empty, then the compiler does not know the length of the array pointed to by a , and pointer arithmetic cannot be performed.

-1
source

Source: https://habr.com/ru/post/1242609/


All Articles