Except when it is the operand of the sizeof
or unary &
operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T
" (T [N]
) is converted ("decays") to an expression of type "pointer to T
" (T *
) and the value of the expression is the address of the first element of the array.
Array objects are not pointers. If you declare an array like
char foo[] = "hello";
it will look like this in memory (addresses are for illustration only):
+–––+
0x1000: |'h'|
+–––+
0x1001: |'e'|
+–––+
0x1002: |'l'|
+–––+
0x1003: |'l'|
+–––+
0x1004: |'o'|
+–––+
0x1005: | 0 |
+–––+
The object foo
is not a pointer; it doesn’t set aside any space for a pointer. The expression foo
is converted to a pointer under most circumstances, including when passed as a function argument:
uc( foo );
What uc
receives is the address of the first element, hence the declaration
void uc( char *s ) { ... }
As for the subscript []
operator, it’s the same thing - the array expression is converted to a pointer to the first element, and the subscript operation is applied to that pointer. The subscript operation is defined as
a[i] == *(a + i)
Given a starting address a
, compute the address of the i
'th object of the pointed-to type (not the i
'th byte) following that address and dereference the result.
So the upshot of that is yes, you can use the []
subscript operator on a pointer expression as well as an array expression.
Pointers don’t have to be represented as integers - on some older segmented architectures, they were represented as a pair of values (page number and offset). Also, pointers to different types may have different representations - e.g., a char *
may not look like an int *
, which may not look like a double *
, etc. On desktop systems like x86 they do, but it’s not guaranteed.
Edit
From a comment:
when initializing an int vector like this: for( int i=0; i < size; ++i); scanf("%d", &vector[i])
does the calculator uses this pointer "mechanism" to cycle trough?
Yes, exactly. scanf
expects the argument corresponding to the %d
conversion specifier to be the address of an int
object, meaning an expression of type int *
. The unary &
operator returns the address of an object, so assuming vector
has been declared
int vector[N]; // for some value of N
then the expression &vector[i]
evaluates to the address of the i
’th element of the array, and the type of the expression is int *
.
Remember that C passes all function arguments by value - the formal parameter in the function definition is a different object in memory than the actual parameter in the function call. For example, given
void foo( T x ) // for any type T
{
x = new_value;
}
void bar( void )
{
T var;
foo( var );
}
the formal parameter x
in foo
is a different object in memory than var
, so the change to x
doesn't affect var
. If we want foo
to able to write to var
, then we must pass a pointer to it:
void foo( T *ptr )
{
*ptr = new_value; // write a new value to the thing ptr *points to*
}
void bar( void )
{
T var;
foo( &var ); writes a new value to var
}
The unary *
operator in *ptr = new_value
dereferences ptr
, so the expression *ptr
in foo
is equivalent to var
:
*ptr == var // T == T
ptr == &var // T * == T *
In a declaration, the *
simply means that the object ptr
has pointer type - it doesn’t dereference, so you can write something like
int x;
int *ptr = &x; // ptr is *not* being dereferenced
int y = 5;
*ptr = y; // ptr *is* being dereferenced