Why can't my parameter be
void example(int Array[][]){ /*statements*/}
Why do I need to specify the column size of the array? Say for example, 3
void example(int Array[][3]){/*statements*/}
My professor said its mandatory, but I was coding before school started and I remembered that there was no syntactical or semantic error when I made this my parameter? Or did I miss something?
When you create a 2D array,
anytype a[3][4]
, in memory what you actually create is3
contiguous blocks of4
anytype objects.a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3]
Now the next question is, why is that so? Because, keeping with the spec and structure of the language,
anytype a[3][4]
actually expands out intoanytype (*a)[4]
, because arrays decay into pointers. And in fact that also expands out intoanytype (*(*a))
, however, you've now completely lost the size of the 2D array. So, you must help the compiler out a bit.If you ask the program for
a[2]
, the program can follow the exact same steps that it does for 1D arrays. It simply can returnthe 3rd element of sizeof(object pointed to)
, the object pointed to here is of size 4 anytype objects.In C/C++, even 2-D arrays are stored sequentially, one row after another in memory. So, when you have (in a single function):
The element you are actually accessing with
a[2][1]
is*(head + 2*3 + 1)
, cause sequentially, that element is after 3 elements of the0
row, and 3 elements of the1
row, and then one more index further.If you declare a function like:
syntactically, it should not be an error. But, when you try to access
array[2][3]
now, you can't tell which element is supposed to be accessed. On the other hand, when you have:you know that with
array[2][3]
, it can be determined that you are actually accessing element at the memory address*(&array[0][0] + 2*5 + 3)
because the function knows the size of the second dimension.There is one other option, as previously suggested, you can declare a function like:
because this way, you are calling the function with the same "information" as before -- the number of columns. You access the array elements a bit differently then: you have to write
*(array + i*cols + j)
where you would usually writearray[i][j]
, causearray
is now a pointer to integer (not to a pointer).When you declare a function like this, you have to be careful to call it with the number of columns that are actually declared for the array, not only used. So, for example:
When it comes to describing parameters, arrays always decay into pointers to their first element.
When you pass an array declared as
int Array[3]
to the functionvoid foo(int array[])
, it decays into a pointer to the beginning of the array i.e.int *Array;
. Btw, you can describe a parameter asint array[3]
orint array[6]
or evenint *array
- all these will be equivalent and you can pass any integer array without problems.In case of arrays of arrays (2D arrays), it decays to a pointer to its first element as well, which happens to be a single dimensional array i.e. we get
int (*Array)[3]
.Specifying the size here is important. If it were not mandatory, there won't be any way for compiler to know how to deal with expression
Array[2][1]
, for example.To dereference that a compiler needs to compute the offset of the item we need in a contiguous block of memory (
int Array[2][3]
is a contiguous block of integers), which should be easy for pointers. Ifa
is a pointer, thena[N]
is expanded asstart_address_in_a + N * size_of_item_being_pointed_by_a
. In case of expressionArray[2][1]
inside a function (we want to access this element) theArray
is a pointer to a single dimensional array and the same formula applies. The number of bytes in the last square bracket is required to findsize_of_item_being_pointed_by_a
. If we had justArray[][]
it would be impossible to find it out and hence impossible to dereference an array element we need.Without the size, pointers arithmetics wouldn't work for arrays of arrays. What address would
Array + 2
produce: advance the address inArray
2 bytes ahead (wrong) or advance the pointer3* sizeof(int) * 2
bytes ahead?There is a similar post regarding this. You can refer below link. Creating Array in C and passing pointer to said array to function Hope it helps.
On the other hand, compiler needs to the second dimension so that it can move "Array" from one pointer to next since the whole memory is arranged in a linear fashion
Actually whether it is a 2d array or a 1d array, it is stored in the memory in a single line.So to say the compiler where should it break the row indicating the next numbers to be in the next rows we are supposed to provide the column size. And breaking the rows appropriately will give the size of the rows.
Let's see an example:
This array a is stored in the memory as:
But since we have specified the column size as 3 the memory splits after every 3 numbers.
In the other case,
The compiler only knows that there are 3 rows but it doesn't know the number of elements in each row so it cannot allocate memory and will show an error.