Search code examples
cpointersmultidimensional-arraypointer-arithmetic

For "int demo[4][2]",why are all these same in magnitude: &demo[1],demo[1],demo+1,*(demo+1) ?What about type?


Just when I had relaxed thinking I have a fair understanding of pointers in the context of arrays,I have fallen face down again over this following program.I had understood how for an array arr,arr and &arr are both same in magnitude,but different in type,but I fail to get a solid grip over the following program's output.I try to visualize it but succeed only partially.I would appreciate if you can give a rigorous and detailed explanation for this thing so that guys like me can be done with this confusion for good.

In the following program,I have used a "2D" array demo[][2].I know that demo[] will be an array of arrays of size 2.I also know that demo used alone will be of type (*)[2].Still I am at a loss about the following :

1) Why is &demo[1] same as demo[1]?Isn't demo[1] supposed to be the address of the second array?What on earth is &demo[1] then and why is it same as address of the second array?

2) I know that the second printf() and fourth are same,as demo[1] is nothing else but *(demo+1).But I've used it so to illustrate this point.How can it be equal to the third printf(),ie,how can demo+1 be equal to *(demo+1)? demo[1] being the same as *(demo+1) is well-known,but how can demo+1 be equal to *(demo+1)? How can "something" be equal to the value at that "something"?

3) And since it just proved I am not very smart,I should stop my guessing game and ask you for a conclusive answer about what are the types for the following :

&demo[1]
demo[1]
demo+1

#include<stdio.h>

int main(void)
{
    int demo[4][2]= {{13,45},{83,34},{4,8},{234,934}};
    printf("%p\n",&demo[1]);
    printf("%p\n",demo[1]);  //Should have cast to (void*),but works still
    printf("%p\n",demo+1);
    printf("%p\n",*(demo+1));
}

OUTPUT:

0023FF28
0023FF28
0023FF28
0023FF28

Solution

  • demo[1] is the second member of the array demo, and is an array itself. Just like any other array, when it's not the subject of the & or sizeof operator, it evaluates to a pointer to its first element - that is, demo[1] evaluates to the same thing as &demo[1][0], the address of the first int in the array demo[1].

    &demo[1] is the address of the array demo[1], and because the address of an array and the address of the first member of that array are necessarily the same location, &demo[1] is equal to &demo[1][0], which is equal to a bare demo[1]. This the key insight - the first element of an array is located at the same place in memory as the array itself, just like the first member of a struct is located at the same place in memory as the struct itself. When you print &demo[1] and demo[1], you're not printing a pointer to the array and an array; you're printing a pointer to the array and a pointer to the first member of that array.

    demo+1 is the address of the second member of demo. *(demo+1) is that member itself (it's the array demo[1]), but because that member is an array, it evaluates to a pointer to its first member. As above, its first member is necessarily collocated with the array itself. It's not that "something" is equal to the value at "something" - because when you use an array in an expression like that, it doesn't evaluate to the array itself.

    • &demo[1] is a pointer to demo[1], which is an array of 2 int. So its type is int (*)[2].
    • demo[1] is an array of 2 int. Its type is int [2]. However, when used in an expression where it is not the subject of type & or sizeof operators, it will evaluate to a pointer to its first member, which is a value with type int *.
    • demo+1 is a pointer to demo[1], and its type is int (*)[2].