Paul said:
When we have a pointer to something that pointer, when dereferenced, must
access whatever it points to.
I have no big trouble with that sentence (I would prefer something
else for "access", like "when dereferenced you get the object poin-
ted to" but I guess I get the meaning and we can agree).
An array of chars when accessed must access a char, you cannot access the
whole array of chars in one operation , unless it is very small.
Now things get hairy. What means "An array of chars when accessed
must access a char." Since it's immediately following the first
sentence I guess it was meant to be "An array of chars when derefe-
renced must access a char". Is that what you meant? If yes, then
it's wrong;-) And the reason is that you seem to labour under the
misconception that an array is more or less a pointer and vice
versa. But they aren't. They are completely different things.
Unfortunately, some design decision, probably made rather early
in the development of C, has led a lot of people to make this
mis-assumption.
In C all objects can be copied with the '=' operator, with two
exceptions. One is rather obvious, you can't copy a function. But
the second exception is arrays. Arrays in C don't have a value that
you could copy with '='. And since they have no value you also
can't pass an array to a function by value, nor can you return an
array from a function. That makes arrays kind of "second-class
citizens" of C (and thus also of C++).
Compare that to structures that, as far as I know, were introduced
much later. You can copy structures using '=', you can pass and
return them from functions like any other object (except functions
and arrays). So they have a "value".
The reason behind this early design decision probably was that
computers tended to have only small amounts of memory back in
the time when C was developed. And arrays tend to hold rather
large amounts of data. Thus you avoided to copy arrays anyway.
And passing an array to a function (or back from it) by value
would have required a copy each time, something that no-one in
his right mind would have done anyway.
Now, since an array can't be passed by value it must be passed by
reference. Unfortunately, the syntax for pointers to array objects
is a bit awkward. Without the "decaying" rule the only way to pass
an array (by reference) would have been something like this:
#include <stdio.h>
void f( int ( *ap )[ ] )
{
printf( "%d\n", ( *ap )[ 3 ] );
}
int main( void )
{
int a[ 5 ] = { 1, 2, 3, 4, 5 };
f( &a );
return 0;
}
While this is perfectly legal C it definitely isn't what you'd want
to see in a language each time you have to pass an array to a func-
tion. And thus someone clever came up with the idea of the "decaying"
arrays in value context: whenever an array object is found where a
value is needed (e.g. when used as an argument to a function,) the
compiler automatically converts it to a pointer to the first element
of that array and passes this as the value to the function - instead
of throwing a tantrum that an array has no value and thus can't be
passed to the function.
This now allows to write 'f(a);' even though 'a' has no value -the
compiler does it's magic and inserts some code that instead passes
the pointer to the first element. And the function f() itself can
then be simplified to
void f( int *ap )
{
printf( "%d\n", ap[ 3 ] );
}
And now everything looks a lot nicer. Also memory allocation
looks a lot simpler than, for example, with
int ( *ip )[ ] = malloc( 5 * sizeof **ip );
One, probably unintended, side effect of this was that people
now started to consider an array as a kind of pointer since in
a lot of places where an array is used it's converted without
any ado by the compiler to a pointer to its first first element.
Add to that that the real pointer-to-array syntax is rather awk-
ward, nearly never used and also has no real advantages and you
have a nice recipe for confusion.
But in another respect there's no deviation from a systematic
approach in C and that is when it comes to pointers to objects.
Even though rarely used, you get a pointer to an array object
when you put the '&' operator in front of it, like for any
other object (with a bit of extra syntax irregularity for
functions since the name of a function in value context is
already treated as a pointer to the function and putting a '&'
in front of the name also results in a pointer to it).
So, the whole "mess" in the end is a result of arrays in some
respect being "second-class" elements in C (and thus in the
languages directly derived from C like C++) and having no values
like other objects. But the type system works for arrays exactly
the same as for other objects, it's just not very useful at the
moment.
char arr[64];
The above is an array of char-type objects.
The array identifier is of type char[64].
Complete agreement here with both statements.
You cannot get a computer system that addresses unlimited amount of memory,
therefore there are no pointers that can point to a complete array, as a
whole.
That's were you wander in the wrong direction. First of all, an
array never has unlimited amounts of memory. The size of each
array is fixed at the moment of its creation (you can't create
an array with an unspecified number of arguments and you can't
change its size afterwards). And there are other compound objects
like structures that can require large amounts of storage and you
probably will agree that there's no problem obtaining and using
pointers to structures.
So, obviously the address of a compound object as a whole
can be defined and stored in a pointer. You use it everyday
with structure pointers. The convention in C is that this
address is taken to be the one of the very first byte of the
compound object in memory. While this is an obvious choice
it would in principle as well have been possible to use some-
thing else, like the address of e.g. the middle of that object
(or one before if the object has odd size). It's just a matter
of coming up with a useful definition of what the address of a
compound obkject is and then stick to it.
And for that reason there is no problem in getting the address
of an array as a whole - like in the case of the structure the
first byte in memory of the array is used (contributing perhaps
a bit to the confusion due to the "decaying" of arrays since the
first byte of the memory of the array is also the address of the
first element of the array).
And if there wouldn't be the syntactic sugar that you can use
something like 'sp->x' to access the member 'x' of a structure
pointed to by 'sp' you'd be using the rather ugly syntax of
'(*sp).x' everywhere. If you compare that to an element access
via an array pointer the similarities becomes rather obvious:
int a[ 4 ] -> element access with 'a[2]' ('[] operator)
struct S s -> member access with 's.x' ('.' operator
int ( *ap )[ 4 ] -> element access with (*ap)[2] ('[]' operator)
struct S *sp -> member access with (*sp).x ('.' operator)
Luckily, you can write '(*sp).x' instead as 'sp->x', but this
syntactic sugar was only implemented for structure pointers,
but not also for the nearly never used array pointers, so you
can't write e.g. 'ap->3'. And nobody complained because nobody
(or hardy anyome) actually was using array pointers.
There is only one type of pointer that can point to the array(NOT point to
array TYPE) and that is char*.
Now all this is fine because I am talking about pointing to an array ( NOT
pointing to an array TYPE), the array is an array of char-types so the
pointer used is a char*
Sorry, you lost me here a bit. The term "pointer to an array TYPE"
is rather strange - a type is an abstract concept and you can't
point to types, you can only point to concrete things like objects.
The pointer-type char (*)[64], when dereferenced does not access the
array.
It does. It "accesses" the array as a whole - like a structure
pointer, when dereferenced, "accesses" the whole structure (per-
haps know my unhapppiness with the term "access" becomes clearer).
With both you then need to write something more (use the '.' or
'[]' operator) to get at the members/elements.
This is a pointer to an array TYPE, not a pointer to "AN ARRAY" of objects.
That's not correct. What you are calling "pointer to an arrayTYPE"
is *the* the pointer to the array object. And if you dereference
it you get the whole array object - to which you then canapply the
'[]' operator to get at the elements. And what you call "pointer to
AN ARRAY" is just a pointer to its first element, as it typically
is generated in situations where an array is used in a context where
a value is required. If you'd replace 'array' by 'structure' every-
where in what you write you'd notice that your resulting statements
aren't true anymore. And an array is, like a structure, just a com-
pound object that can be pointed to.
Now I hope you can see the difference between
a) pointer to AN ARRAY.
b) pointer to an array TYPE.
I guess you made a big step in accepting that there are two types
of pointers (whatever you call them). Now you only have to get rid
of the mis-conceptions regarding C's ability to point to compound
objects when it comes to arrays. And that step is the smaller one
since I'm sure the concept is well-known and -understood by you in
the case of structures. Just think of an array as a funny kind of
structure and disregard for a moment that for some purely histo-
rical reasons an array as a whole has no "value" and you're there.
Just try to keep in mind that an array isn't a pointer of any kind
and that an array always has a fixed size (like a structure).
(I actually have my problems in seeing a structure as a "value",
but then they are treated everywhere in C as having a "value",
so I've got to accept that. But if I can accept that it becomes
more mysterious why an array didn't got one, that seems to be
unfair to arrays, especially given that they are used much more
often;-)