Reputation: 570
I have created a 2D array, and tried to print certain values as shown below:
int a[2][2] = { {1, 2},
{3, 4}};
printf("%d %d\n", *(a+1)[0], ((int *)a+1)[0]);
The output is:
3 2
I understand why 3
is the first output (a+1
points to the second row, and we print its 0th
element.
My question is regarding the second output, i.e., 2
. My guess is that due to typecasting a
as int *
, the 2D array is treated like a 1D array, and thus a+1
acts as pointer to the 2nd
element, and so we get the output as 2
.
Are my assumptions correct or is there some other logic behind this?
Also, originally what is the type of a
when treated as pointer int (*)[2]
or int **
?
Upvotes: 16
Views: 645
Reputation: 106012
Are my assumptions correct or is there some other logic behind this?
Yes.
*(a+1)[0]
is equivalent to a[1][0]
.
((int *)a+1)[0]
is equivalent to a[0][1]
.
Explanation:
a
decays to pointer to first element of 2D array, i.e to the first row. *a
dereferences that row which is an array of 2 int
. Therefore *a
can be treated as an array name of first row which further decay to pointer to its first element, i.e 1
. *a + 1
will give the pointer to second element. Dereferencing *a + 1
will give 1
. So:
((int *)a+1)[0] == *( ((int *)a+1 )+ 0)
== *( ((int *)a + 0) + 1)
== a[0][1]
Note that a
, *a
, &a
, &a[0]
and &a[0][0]
all have the same address value although they are of different types. After decay, a
is of type int (*)[2]
. Casting it to int *
just makes the address value to type int *
and the arithmetic (int *)a+1
gives the address of second element.
Also, originally what is the type of a when treated as pointer
(int (*)[2]
orint **
?
It becomes of type pointer to array of 2 int
, i.e int (*)[2]
Upvotes: 9
Reputation: 3069
The key thing to recognize here is that the a
there holds the value of the address where the first row is located at. Since the whole array starts from the same location as that, the whole array also has the same address value; same for the very first element.
In C
terms:
&a == &a[0];
&a == &a[0][0];
&a[0] == &a[0][0];
// all of these hold true, evaluate into 1
// cast them if you want, looks ugly, but whatever...
&a == (int (*)[2][2]) &a[0];
&a == (int (*)[2][2]) &a[0][0];
&a[0] == (int (*)[2]) &a[0][0];
For this reason, when you cast the a
to int *
, it simply becomes 1-to-1 equivalent to &a[0][0]
both by the means of type and the value. If you were to apply those operations to &a[0][0]
:
(&a[0][0] + 1)[0];
(a[0] + 1)[0];
*(a[0] + 1);
a[0][1];
As for the type of a
when treated as a pointer, although I am not certain, should be int (*)[2]
.
Upvotes: 0
Reputation: 310970
When you wrote expression
(int *)a
then logically the original array can be considered as a one-dimensional array the following way
int a[4] = { 1, 2, 3, 4 };
So expression a
points to the first element equal to 1 of this imaginary array. Expression ( a + 1 )
points to the second element of the imaginary array equal to 2 and expression ( a + 1 )[0]
returns reference to this element that is you get 2.
Upvotes: 10
Reputation: 11058
A 2D-array is essentially a single-dimensional array with some additional compiler's knowledge.
When you cast a
to int*
, you remove this knowledge, and it's treated like a normal single-dimensional array (which in your case looks in memory like 1 2 3 4
).
Upvotes: 3