Declaring multidimensional Arrays: Pointer or Array Definiton - c

What's the difference between declaring multidimensional arrays like this:
int a[5][5];
or this
int* a[5];
?
Which one is better to use? Thanks.

Both may be used to declare 2-dimensional arrays.
In the first case, 25 int elements are allocated in a contiguous region in memory.
In this case the expression a[i][j] is translated by the compiler to *(a + i*5 + j).
The second one allocates 5 pointers to int. You can make it work as a two dimensional array by allocating vectors of int and making these pointers point to these vectors.
In this case a[i][j] means get the pointer that a[i] points to, then look up the 5th element in that vector. I.e. a[i][j] is translated to *(a[i] + j).
Note that in the second case, rows need not be of the same length.

int a[5][5]; says that the compiler should allocate enough memory to store 25 ints, and to treat it as a two-dimensional array called a.
int* a[5]; says that the compiler should allocate enough memory to store 5 pointers to integers, and treat it as an array of pointers called a. To actually use this as a two-dimensional array, you will have to allocate more memory and initialize those pointers to point at it. For example:
int * a[5];
for(int i = 0; i < 5; i++){ a[i] = malloc(sizeof(int) * 5); }
Without knowing your requirements it's hard to say which one is better for you. The second one allows you to efficiently swap two rows and is generally more flexible, but it takes more code to allocate and free the data structure.

The first one you are declaring bidimensional array (an array of arrays).
The second you're declaring an array of pointers to ints which can used as multidimensional array.
Is int *array[32] a pointer to an array of 32 ints, or an array of 32 pointers to int? Does it matter?
Take a look at http://www.cplusplus.com/doc/tutorial/arrays/ for declaring multidimensional arrays

Which is better apple or orange ?
this notation int a[ROWS][COLS]is used to create rectangular 2D array which dimensions are known at declaration time.
And this int * a[ROWS] notation is used when number of columns are unknown at 2D array declaration time OR number of columns can vary in run-time OR simply one wants to create non-rectangular (jagged) array like this:
1 2 3 4
4 6
7 1 1 1 5 6 7
9

Related

Memory allocation when casting to a VLA type

I am puzzled by the memory allocation and accesses to a matrix of pointers in an application I am working in.
There is a matrix defined as:
typedef double (*foo)[n/m][m][m];
Which I understand to be a three-dimensional matrix storing pointers to doubles. The memory allocation for all dimensions is done automatically.
Nonetheless, the following appears:
foo bar = (foo) malloc(sizeof(double) * n * n);
What exactly is this cast doing?. Furthermore, why do we need to allocate memory for these doubles?. I would think the matrix only contains pointers, which would later be initialized with the memory addresses of doubles declared separately.
Finally, I am, also confused by the way this matrix is accessed during its initialization:
bar[i/m][j/m][i%m][j%m] = value;
Where i and j are smaller than N. Mainly, I would like to know what the fourth index is adressing.
Thank you so much in advance for your help!
This double (*foo)[n/m][m][m] creates 1 single pointer foo that will be used to point to 3 dimensional arrays containing values of type double, where the size of each of the 3 dimensions are n/m, m and m respectively, for a total of (n/m)*m*m = n*m double values in each 3 dimensional array.
Note that you can use pointer's arithmetic over foo, so if foo points to one 3 dimensional array, then foo+1 will point to the next 3 dimensional array.
In pointer notation you would do (*(foo+1))[0][0][0] to access the first double value of the second 3 dimensional array, and you can rewrite this using array notation as foo[1][0][0][0] to do the same thing. So now you can see that by iterating over foo you are iterating over the 4th dimension of a 4 dimensional array.
From the code we see that it allocated n*n double values for this 4 dimensional array. So, as we don't know the size of the forth dimension, we could say that the dimensions of the array are something like [x][n/m][m][m] where x is the unknown size. But we do know that this 4 dimensional array will have n*n elements, so to find x we need to solve x*(n/m)*m*m = n*n, therefore x = n/m, and the dimensions are [n/m][n/m][m][m].

C: size of *array[x]?

I have a question that should be fairly straightforward (I hope).
In c, the size of an array delcared as int array[10][10];,
for example, I understand as having 10 spots in which to store 10 integers. However, what's the size of an array declared as int *array[10];? I know that *array has 10 elements, but how many elements does array have?
This is a hole in my understanding I would really like to clear up. Thanks for any help!
int *array[10]; is an array of 10 int *s, so the number of elements is 10.
To elaborate, for int *array[10];, ty type of array variable is int * [10], an array of 10 elements of type pointer to integers.
The array size would be 10 * sizeof pointer-to-integer-in-your-platform.
You have to understand the declaration in C.
Start dividing it in parts:
int array[10][10];
array is the name of the variable, the part [10] means that it is an array of 10 arrays of int, each array holding 10 elements (the second [10]).
Now:
int * array[10];
array is the name of the variable, the part [10] means that it is an array of 10 elements of type int * (integer pointers not integers as before).
The sizes in the firs case will be 10 times the size of an array of 10 integers = the space required for 100 integers.
In the second case will be the size to hold 10 pointers to integer.
As side note maybe your confusion comes from the fact that C allows access to elements of both declaration in the same way. I.e. the following will get the 5th integer of the second array:
int b = array[2][5];
But the difference remains substantial because in the first declaration the compiler will allocate contiguous space to hold all 100 integers (organized, as per C allocating method, as 10 arrays of 10 integers each in succession), in the second case will be allocated only an array of 10 pointers each pointing to the location of an array of 10 integers. And the 10 arrays will not be allocated, nor the pointers initialized.
In that case it is programmer responsibility to allocate 10 arrays of int and assign the address of each one to the array of pointers.
Another point to clarify (thanks to alk to have pointed it out) is that in the case of the array of pointers the second dimension is undefined, meaning that each array of int pointed can be of 1, 10, 1000 or whatever elements.
how many elements does array have?
int *array[10];
array is array of 10 pointers to int, the same as int* array[10] - so array has 10 elements (each element being a pointer).

C - Pass variable length array of strings to function and modify strings inside function [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 6 years ago.
int main()
{
matrix[2][4] = {{11,22,33,99},{44,55,66,110}};
int **ptr = (int**)matrix;
printf("%d%d",**matrix,*ptr);
}
But when a 2-d array is passed as a parameter it is typecasted into (*matrix)[2] ..
what type does the compiler store this array as... is it storing as a 2-d array or a double pointer or an pointer to an array .. If it is storing as an array how does it interprets differently at different situations like above. Please help me understand.
Is 2d array a double pointer?
No. This line of your program is incorrect:
int **ptr = (int**)matrix;
This answer deals with the same topic
If you want concrete image how multidimensional arrays are implemented:
The rules for multidimensional arrays are not different from those for ordinary arrays, just substitute the "inner" array type as element type. The array items are stored in memory directly after each other:
matrix: 11 22 33 99 44 55 66 110
----------- the first element of matrix
------------ the second element of matrix
Therefore, to address element matrix[x][y], you take the base address of matrix + x*4 + y (4 is the inner array size).
When arrays are passed to functions, they decay to pointers to their first element. As you noticed, this would be int (*)[4]. The 4 in the type would then tell the compiler the size of the inner type, which is why it works. When doing pointer arithmetic on a similar pointer, the compiler adds multiples of the element size, so for matrix_ptr[x][y], you get matrix_ptr + x*4 + y, which is exactly the same as above.
The cast ptr=(int**)matrix is therefore incorrect. For once, *ptr would mean a pointer value stored at address of matrix, but there isn't any. Secondly, There isn't a pointer to matrix[1] anywhere in the memory of the program.
Note: the calculations in this post assume sizeof(int)==1, to avoid unnecessary complexity.
No. A multidimensional array is a single block of memory. The size of the block is the product of the dimensions multiplied by the size of the type of the elements, and indexing in each pair of brackets offsets into the array by the product of the dimensions for the remaining dimensions. So..
int arr[5][3][2];
is an array that holds 30 ints. arr[0][0][0] gives the first, arr[1][0][0] gives the seventh (offsets by 3 * 2). arr[0][1][0] gives the third (offsets by 2).
The pointers the array decays to will depend on the level; arr decays to a pointer to a 3x2 int array, arr[0] decays to a pointer to a 2 element int array, and arr[0][0] decays to a pointer to int.
However, you can also have an array of pointers, and treat it as a multidimensional array -- but it requires some extra setup, because you have to set each pointer to its array. Additionally, you lose the information about the sizes of the arrays within the array (sizeof would give the size of the pointer). On the other hand, you gain the ability to have differently sized sub-arrays and to change where the pointers point, which is useful if they need to be resized or rearranged. An array of pointers like this can be indexed like a multidimensional array, even though it's allocated and arranged differently and sizeof won't always behave the same way with it. A statically allocated example of this setup would be:
int *arr[3];
int aa[2] = { 10, 11 },
ab[2] = { 12, 13 },
ac[2] = { 14, 15 };
arr[0] = aa;
arr[1] = ab;
arr[2] = ac;
After the above, arr[1][0] is 12. But instead of giving the int found at 1 * 2 * sizeof(int) bytes past the start address of the array arr, it gives the int found at 0 * sizeof(int) bytes past the address pointed to by arr[1]. Also, sizeof(arr[0]) is equivalent to sizeof(int *) instead of sizeof(int) * 2.
In C, there's nothing special you need to know to understand multi-dimensional arrays. They work exactly the same way as if they were never specifically mentioned. All you need to know is that you can create an array of any type, including an array.
So when you see:
int matrix[2][4];
Just think, "matrix is an array of 2 things -- those things are arrays of 4 integers". All the normal rules for arrays apply. For example, matrix can easily decay into a pointer to its first member, just like any other array, which in this case is an array of four integers. (Which can, of course, itself decay.)
If you can use the stack for that data (small volume) then you usually define the matrix:
int matrix[X][Y]
When you want to allocate it in the heap (large volume), the you usually define a:
int** matrix = NULL;
and then allocate the two dimensions with malloc/calloc.
You can treat the 2d array as int** but that is not a good practice since it makes the code less readable. Other then that
**matrix == matrix[0][0] is true

Can't use fixed array in 'dynamic array' in struct [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 6 years ago.
int main()
{
matrix[2][4] = {{11,22,33,99},{44,55,66,110}};
int **ptr = (int**)matrix;
printf("%d%d",**matrix,*ptr);
}
But when a 2-d array is passed as a parameter it is typecasted into (*matrix)[2] ..
what type does the compiler store this array as... is it storing as a 2-d array or a double pointer or an pointer to an array .. If it is storing as an array how does it interprets differently at different situations like above. Please help me understand.
Is 2d array a double pointer?
No. This line of your program is incorrect:
int **ptr = (int**)matrix;
This answer deals with the same topic
If you want concrete image how multidimensional arrays are implemented:
The rules for multidimensional arrays are not different from those for ordinary arrays, just substitute the "inner" array type as element type. The array items are stored in memory directly after each other:
matrix: 11 22 33 99 44 55 66 110
----------- the first element of matrix
------------ the second element of matrix
Therefore, to address element matrix[x][y], you take the base address of matrix + x*4 + y (4 is the inner array size).
When arrays are passed to functions, they decay to pointers to their first element. As you noticed, this would be int (*)[4]. The 4 in the type would then tell the compiler the size of the inner type, which is why it works. When doing pointer arithmetic on a similar pointer, the compiler adds multiples of the element size, so for matrix_ptr[x][y], you get matrix_ptr + x*4 + y, which is exactly the same as above.
The cast ptr=(int**)matrix is therefore incorrect. For once, *ptr would mean a pointer value stored at address of matrix, but there isn't any. Secondly, There isn't a pointer to matrix[1] anywhere in the memory of the program.
Note: the calculations in this post assume sizeof(int)==1, to avoid unnecessary complexity.
No. A multidimensional array is a single block of memory. The size of the block is the product of the dimensions multiplied by the size of the type of the elements, and indexing in each pair of brackets offsets into the array by the product of the dimensions for the remaining dimensions. So..
int arr[5][3][2];
is an array that holds 30 ints. arr[0][0][0] gives the first, arr[1][0][0] gives the seventh (offsets by 3 * 2). arr[0][1][0] gives the third (offsets by 2).
The pointers the array decays to will depend on the level; arr decays to a pointer to a 3x2 int array, arr[0] decays to a pointer to a 2 element int array, and arr[0][0] decays to a pointer to int.
However, you can also have an array of pointers, and treat it as a multidimensional array -- but it requires some extra setup, because you have to set each pointer to its array. Additionally, you lose the information about the sizes of the arrays within the array (sizeof would give the size of the pointer). On the other hand, you gain the ability to have differently sized sub-arrays and to change where the pointers point, which is useful if they need to be resized or rearranged. An array of pointers like this can be indexed like a multidimensional array, even though it's allocated and arranged differently and sizeof won't always behave the same way with it. A statically allocated example of this setup would be:
int *arr[3];
int aa[2] = { 10, 11 },
ab[2] = { 12, 13 },
ac[2] = { 14, 15 };
arr[0] = aa;
arr[1] = ab;
arr[2] = ac;
After the above, arr[1][0] is 12. But instead of giving the int found at 1 * 2 * sizeof(int) bytes past the start address of the array arr, it gives the int found at 0 * sizeof(int) bytes past the address pointed to by arr[1]. Also, sizeof(arr[0]) is equivalent to sizeof(int *) instead of sizeof(int) * 2.
In C, there's nothing special you need to know to understand multi-dimensional arrays. They work exactly the same way as if they were never specifically mentioned. All you need to know is that you can create an array of any type, including an array.
So when you see:
int matrix[2][4];
Just think, "matrix is an array of 2 things -- those things are arrays of 4 integers". All the normal rules for arrays apply. For example, matrix can easily decay into a pointer to its first member, just like any other array, which in this case is an array of four integers. (Which can, of course, itself decay.)
If you can use the stack for that data (small volume) then you usually define the matrix:
int matrix[X][Y]
When you want to allocate it in the heap (large volume), the you usually define a:
int** matrix = NULL;
and then allocate the two dimensions with malloc/calloc.
You can treat the 2d array as int** but that is not a good practice since it makes the code less readable. Other then that
**matrix == matrix[0][0] is true

Why do we need to specify the column size when passing a 2D array as a parameter?

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 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 function void foo(int array[]), it decays into a pointer to the beginning of the array i.e. int *Array;. Btw, you can describe a parameter as int array[3] or int array[6] or even int *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. If a is a pointer, then a[N] is expanded as start_address_in_a + N * size_of_item_being_pointed_by_a. In case of expression Array[2][1] inside a function (we want to access this element) the Array 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 find size_of_item_being_pointed_by_a. If we had just Array[][] 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 in Array 2 bytes ahead (wrong) or advance the pointer 3* sizeof(int) * 2 bytes ahead?
In C/C++, even 2-D arrays are stored sequentially, one row after another in memory. So, when you have (in a single function):
int a[5][3];
int *head;
head = &a[0][0];
a[2][1] = 2; // <--
The element you are actually accessing with a[2][1] is *(head + 2*3 + 1), cause sequentially, that element is after 3 elements of the 0 row, and 3 elements of the 1 row, and then one more index further.
If you declare a function like:
void some_function(int array[][]) {...}
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:
void some_function(int array[][5]) {...}
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:
void some_function(int *array, int cols) { ... }
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 write array[i][j], cause array 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:
int main(){
int a[5][5];
int i, j;
for (i = 0; i < 3; ++i){
for (int j=0; j < 3; ++j){
scanf("%d", &a[i][j]);
}
}
some_function(&a[i][j], 5); // <- correct
some_function(&a[i][j], 3); // <- wrong
return 0;
}
C 2018 6.7.6.2 specifies the semantics of array declarators, and paragraph 1 gives constraints for them, including:
The element type shall not be an incomplete or function type.
In a function declaration such as void example(int Array[][]), Array[] is an array declarator. So it must satisfy the constraint that its element type must not be incomplete. Its element type in that declaration is int [], which is incomplete since the size is not specified.
There is no fundamental reason the C standard could not remove that constraint for parameters that are about to be adjusted to pointers. The resulting type int (*Array)[] is a legal declaration, is accepted by compilers, and can be used in the form (*Array)[j].
However, the declaration int Array[][] suggests that Array is at least associated with a two-dimensional array, and hence is to be used in the form Array[i][j]. Even if the declaration int Array[][] were accepted and were adjusted to int (*Array)[], using it as Array[i][j] would not be possible because the subscript operator requires that its pointer operand be a pointer to a complete type, and this requirement is not avoidable as it is needed to calculate the address of the element. Thus, keeping the constraint on the array declarator makes sense, as it is consistent with the intended expression that the argument will be a two-dimensional array, not just a pointer to one one-dimensional array.
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:
int a[][3]={ 1,2,3,4,5,6,7,8,9,0 };
This array a is stored in the memory as:
1 2 3 4 5 6 7 8 9 0
But since we have specified the column size as 3 the memory splits after every 3 numbers.
#include<stdio.h>
int main() {
int a[][3]={1,2,3,4,5,6},i,j;
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
OUTPUT:
1 2 3
4 5 6
In the other case,
int a[3][]={1,2,3,4,5,6,7,8,9,0};
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.
#include<stdio.h>
int main() {
int a[3][]={1,2,3,4,5,6},i,j;
for(i=0;i<3;i++)
{
for(j=0;j<2;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
OUTPUT:
c: In function 'main':
c:4:8: error: array type has incomplete element type 'int[]'
int a[3][]={1,2,3,4,5,6},i,j;
^
As we know, we can pass a variable as an argument(s) in a function. Similarly, we can pass two-dimensional arrays in C++.
C++ does not allow us to pass an entire array as an argument to a function. However, we can pass a pointer to an array by specifying the array's name without an index.
We can pass a 2D array to a function by specifying the size of the columns of a 2D array. One of the important things to remember here is that the size of rows is optional but the size of the column should not be left empty else the compiler will show an error. A 2D array is stored in the memory in a single line. So, to say the compiler where should it break the row indicating the following numbers to be in the next rows we are supposed to provide the column size. And breaking the rows appropriately will automatically give the size of the rows.
source: https://www.scaler.com/topics/two-dimensional-array-in-cpp/
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
I thought this was a cool approach. If you take this as the formula to calculate the address of an element in the array:
a[i][j] = baseArrayAddress + (i + (colSize + elementSize)) + (j * (elementSize))
Then you can see that the only thing the compiler needs to know (which it can't otherwise infer) is the size of the column, thus you need to provide it as the programmer so the algorithm can run to calculate the offset.
The row number only acts as a multiplier and is provided by the programmer when trying to dereference an array location.
When you create a 2D array, anytype a[3][4], in memory what you actually create is 3 contiguous blocks of 4 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 into anytype (*a)[4], because arrays decay into pointers. And in fact that also expands out into anytype (*(*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 return the 3rd element of sizeof(object pointed to), the object pointed to here is of size 4 anytype objects.

Resources