They aren't the same thing.
An array is an object consisting of a sequence of one or more contiguous elements, all of the same type. A 2-dimensional array is nothing more or less than an array of arrays.
The name of an array is an expression. Like any expression of array type, it is, in most but not all contexts, implicitly converted to a pointer to the array's first element. The exceptions are when it's the operand of sizeof
(sizeof arr
yields the size of the array object, not the size of a pointer) and when it's the operand of unary &
(&arr
yields the address of the entire array).
The address of an array is like the address of any object. It refers to a particular memory address, and it has a type: pointer to the array type. For example, given:
int arr[10];
the expression arr
(if it's not the operand of &
or sizeof
) yields the address of arr[0]
, and is of type int*
. The expression &arr
yields the address of the entire array; it's the same memory location, but it's of type int (*)[10]
, or "pointer to array of 10 int
s".
The value of an array is generally not something that's you can directly refer to. It consists of the values of the elements of the array.
Now let's look at your program:
#include <stdio.h>
int main(void)
{
int array[4][2]={1,2,3,4,5,6,7,8};
This is more clearly written as:
int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
printf("%d %d\n",
&array[0][0], array[0][0]);
array[0][0]
is an int
object, so &array[0][0]
is its address, and is of type int*
. The correct way to print an address (pointer value) is to use the %p
format; it expects an argument of type void*
, so you should convert it.
printf("%p %d\n", (void*)&array[0][0], array[0][0]);
printf("%d %d %d %d\n",
array, &array, *array, **array);
array
is an expression of array type, so it "decays" to a pointer to that array's first element. That element is of type int[2]
, so the pointer is of type int(*)[2]
. Again, you should use %p
and convert to void*
.
&array
is the address of the entire array. It's of type int(*)[4][2]
.
In *array
, the subexpression array
decays to a pointer. *
then dereferences that pointer, which gives us an object of type int[2]
(the first element of the array). That's an expression of array type, so it decays again to a pointer to that array's first element. It's of type int*
.
In **array
, *array
is evaluated as above; it's a pointer to an int
object. The next *
dereferences that pointer, yielding an int
value.
All the pointer values you've printed point to the same memory address, but they're variously of type int*
, int(*)[2]
, or int(*)[2][4]
. Each of these pointers, when converted to void*
, yields the same value, and all of them
}
Putting this together, here's a corrected version of your program:
#include <stdio.h>
int main(void)
{
int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
printf("%p %d\n",
(void*)&array[0][0], array[0][0]);
printf("%p %p %p %d\n",
(void*)array, (void*)&array, (void*)*array, **array);
}
The output on my (64-bit) system is:
0x7fffc5070b30 1
0x7fffc5070b30 0x7fffc5070b30 0x7fffc5070b30 1
The relationship between arrays and pointers in C can be confusing. Much of the confusion can be cleared up by reading section 6 of the comp.lang.c FAQ.