Imagine the following:
int A[10];
int* B = 0;
Evaluating A yields the address of the first element in the array. Evaluating the address of A also yields the address of the first element in the array.
&A == (int*)&A[0]
&A == A
(int*)&A[0] == A
All three of these expressions will evaluate to true
B = A;
B = (int*)
B=&A[0]
The above three statements are all equivalent because array references behave like pointers when they are evaluated as part of an expression.
Unlike pointers, the array reference itself is not assigned memory, only the array elements are assigned memory. The array reference is used as a handle to the first element in the array and all references are resolved at compile time. A pointer can be reseated (assigned a new value), an array cannot.
B = A; is valid
A = B; is not valid
looking at this another way
int A[10]; will consume 40 bytes of memory assuming a 4 byte integer
int* B = malloc(sizeof(int) * 10); will consume 44 bytes of memory assuming 4 byte integers and 4 byte addresses