I am learning now c and i am studying pointers. I have read some examples and I come up with this:
#include <stdio.h>
int main ()
{
float balance[10][5];
float *p;
p = (float *) balance;
*(p + 16) = 200.0; //init the balance[3][1] with the value 200.0
printf("%f\n", balance[3][1]);
return 0;
}
My question is this. Why I have to cast the balance with a (float *) ? Is this because the array is 2 dimensions? So the pointer is also 2 dimensions? So I have to transform it to a 1 dimension ?
Why i have to cast the balance with a (float *) ?
This is because p is of type float * while balance is of type float (*)[5] after decaying to the pointer.
is this because the array is 2 dimensions?
Yes.
so the pointer is also 2 dimensions?
balance decays to float (*)[5].
so i have to transform it to a 1 dimension ?
Yes.
This code is an ugly hack, and will only serve to confuse you, now and when you come back to look at this code in the future. The idea behind pointer arithmetic is to make accessing arrays easier, not harder. If you change
float *p;
to
float **p;
your pointer is now a double pointer, which means that when you use the indirection operator (*) once, you get another pointer. The array you've created looks like this:
[0,0][0,1][0,2][0,3][0,4]
[1,0][1,1][1,2][1,3][1,4]
[2,0][2,1][2,2][2,3][2,4]
[3,0][3,1][3,2][3,3][3,4]
[4,0][4,1][4,2][4,3][4,4]
[5,0][5,1][5,2][5,3][5,4]
[6,0][6,1][6,2][6,3][6,4]
[7,0][7,1][7,2][7,3][7,4]
[8,0][8,1][8,2][8,3][8,4]
[9,0][9,1][9,2][9,3][9,4]
Since you have two levels of indirection, the first pointer will point to your row, and the second one will point to your column. Since indirection is done backwards, that means that in pointer notation the innermost element is the element that would be furthest left in array notation.
arr[ROW][COL] === *(*(p + ROW) + COL)
Now, if you want to access elements, you can do that using array notation arr[ROW][COL], or with pointer arithmetic. With a double pointer, there are two levels of indirection. So whereas you had to use
p = (float *) balance;
*(p + 16)
to get the location you wanted, it would actually be a lot easier (in my opinion) to simply write
p = balance;
*(*(p + 3) + 1)
because now you're using pointer arithmetic similarly to array indexing, and it's easier to tell just at a glance which element you want to point at.
As far as casting a double pointer to a single pointer, it's really easier to just handle the double pointer in the first place, and that's all that the name of an array is.
int arr[ROW][COL] = {0};
int **p_arr = arr; /* Valid operation. arr without array notation is a double pointer */
This example demonstrates how arrays are allocated in memory. A two-dimensioanl array is allocated by rows that is after the first row there is the second row of the array in the memory. As the memory for arrays is allocated as one extent then you can interpretated it as a one-dimensionale array.
The array in your example has in fact 50 elements (10 * 5). As the rows are accomodated sequentially in the memory then the position of the element balance[3][1] can be calculated as 3 * 5 + 1 that is equal to 16. So if you will consider that extent of the memory as one dimensional array then the corresoponding element can be written as p[16] or (that is the same) as *(p + 16).
One useful trick of such interpretation of a two-dimensional array can be applied to sorting of a two-dimensional array. It is much simpler to sort a two-dimensional array as one-dimensional array using standard sort functions.
Why I have to cast the balance with a (float *)
You don't have to, you can use it simply as an array, just as is done in the printf(). I would advise you to refrain from combining flat access and multidimensional access.
here the variable "balance" stores the base address of the 2 dimensional array..
what is a pointer?
A variable which store the address is called pointer
right!!
'p' is single floating pointer which stores the address of a floating variable but here 'balance' is a floating array variable.
what you have did is, typecasting the 2D array variable to a pointer as a 1D array...i.e. according to the pointer variable 'p' what you assigned in 'balance' which is a 2D array has now become a 1D array...
if you assign pointer lyk this
float **p;
then
p=balance; is a valid statement and the pointer treat this as a 2D array.
Related
Do I need to do type casting when I want to index a specific array element of a two dimensional array manually with pointer arithmetic.If so why? Here's what I mean:
float *p;
float balance[5][2]={2.34,
5.66,7.85,12.56,9.87,76.22,56.55,21.02,66.12,10.001};
p=(float *) balance; //Do I need this type casting and if so why?
printf("%.2f",*(p+(3*2)+1));
Balance is a 2D array that is an array of arrays. It will decay like any array to a pointer to its first element... but that element is still an array and not a float!
That is the reason why you need a cast here, but in fact casting a pointer to an array to a pointer to its first element is not really standard wise. The correct way is to dereference balance: it will be an 1D array which will nicely decay to a pointer to the first float:
p = *balance; // no cast required here
That being said, on a pedantic point of view, the next line (*(p+(3*2)+1)) aliases a 2D 2x5 array to an 1D array of size 10. The result is undefined per the standard as soon as the index is larger that the row size here 2. Of course all common implementation allow it for compatibility with old code, but you really should wonder why you need it and avoid that if you can.
The correct and conformant way would be:
float (*pp)[2];
float balance[5][2] = { 2.34,
5.66,7.85,12.56,9.87,76.22,56.55,21.02,66.12,10.001 };
pp = balance;
printf("%.2f\n", pp[3][1]);
This question already has answers here:
Difference between pointer to pointer and pointer to array?
(3 answers)
Closed 5 years ago.
Can anyone please tell if both the entity - i.e.
2-D array char array[][9] and
array of pointers char *array[9] are same or different??
They are different.
The most prominent difference is that in the case of the array the elements will be laid out contigously in memory but in the case of the array of pointers they will not.
To be able to use the elements of the array of pointers, you need to make them point to some valid memory, you can do that either by using malloc() or by pointing to an array for example. In both cases the elements of the potential array the pointer points to are not contiguous.
Your confusion might be due to the fact that arrays can be syntactically used as pointers, because if you pass an array to a function expecting a pointer then, it is equivalent to a pointer that points to the first element of such array.
Also,
int x[3] = {1, 2, 3};
int *y = x;
is valid and you can use y as if it was an array even though it's not. It's a pointer, and you can use it to traverse the elements of the array x using pointer arithmetic.
One way of expressing such arithmetic is by the use of the [] syntax, in fact
int value = y[1]
is equivalent to performing a pointer arithmetic operation on y and dereferencing it, exactly equivalent to
int value = *(y + 1);
i.e. move to the element that is (1×sizeof *y) bytes after the beginning of y and get the value there.
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
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
In C, two dimensional arrays are stored in the way just like linear arrays, but they are indexed using a double pointer. That is, if we define
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}}.
a first points to something like
{p1 = 0x7fff5fbffb58 , p2 = 0x7fff5fbffb70, p3 = 0x7fff5fbffb88}
then p1 points to 1, p2 points to 4 and p3 points to 7.
So why don't compilers allow for a conversion from the two dimensional array to the double pointer which is theoretically possible? Although 2-D arrays are stored one by one, but the index information can always be passed to an arbitrary double pointer.
It's not theoretically possible. 2d arrays are not indexed using a double pointer - the compiler convert it to one index. For example, if you have int a[3][5], and you access a[i][j], the compiler convert it to ((int[])a)[5*i+j]. (Your explanation is completely wrong)
Because of all of that, if you want to convert int[][] to int**, you need to allocate memory to save the addresses of all the sub-arrays, and get the address of it. Just (int**)a will not work.
Your example illustrates the reason why compilers cannot do it: the values of p1, p2, and p3 are calculated, not stored. The compiler knows the address of p1, and calculates the other two with the knowledge of the array size in hand. With double pointers, on the other hand, all three pointers would need to be stored in sequential memory locations, forming an array of pointers.
Converting int[][] to int** would require introducing array of int pointers full of data. We love c for not taking such liberties when not explicitly asked for.
Because C says so.
(C99, 6.3.2.1p3) "Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue."
This conversion rule is not recursive for array of array.
The value of an object of type int [N][M] is of type int (*)[M] after conversion.
Because are two different things. int a[3][3], in the memory is an array of 9 elements.
int** you should have an array of pointers with 3 elements that each one of them will point to another array, that will contains the data.