This defines an array of a certain size:
int array1[10];
This defines a pointer to integer:
int * array2;
Both definitions allocate some memory. The first one allocates space to hold 10 ints. The second one allocates space to hold a pointer to integer.
When the array1
is used in an expression as an rvalue, it degenerates to a pointer. So using array1
rvalue is equivalent to taking its address: &array1
. In an expression, array1
and array2
rvalues are equivalent: they act as pointer-to-int values. The difference is that you can't use array1
as an lvalue: you can't assign to it, and you can't modify it - because it's not a pointer you can write to. You can certainly, of course, modify the values pointed-to by either array1
-acting-as-a-pointer, or by array2
.
Both definitions above give you uninitialized variables: the contents of array1
are not defined, neither are the contents of array2
. So, for example, it'd be an error to dereference the array2
pointer before a value was assigned to it.
You can set array2
to the address of the 10 integer-long area allocated in array1
, and both are then equivalent:
int array1[10];
int * array2 = array1;
array1[0] = 1;
array2[0] ++; // Increment the first item of the array
assert(array1[0] == 2);
But while you can certainly make array2
point to the second item in the first array, you can't change where array1
points to:
array2 ++; // Increment the pointer so that it points to the second item of the array
assert(array2 == &array1[1]);
array1 ++; // Triggers a compile-time error diagnostic
The assert
, from #include <assert.h>
, is simply a way to assert certain facts. If they prove false at runtime, the program will abort. It's also a way to succinctly express, in the C language, that certain things are true at certain points in the program. It's better than writing comments, since the assertion will be checked for you in a debug build, at runtime.