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