1) Misconception :
Whenever an array is declared in C language, a pointer to the first element of the array is created (
The short answer is yes...except for sometimes. Usually after an array is declared, each time its name is used, it is converted to a pointer to the array object's first element. However there are some cases where this does not occur. These cases where this does not occur can be found in @KeithThompson's answer here.
Similarly to your array, a function type will also be converted to a pointer value...except for sometimes. The cases where this does not occur again can be found at @KeithThompson's answer again. here.
There is a much better way to think about it. An expression of array type (which includes: an array name, a dereference of a pointer to an array, a subscripting of a two-dimensional array, etc.) is just that -- an expression of array type. It is not an expression of pointer type. However, the language provides an implicit conversion from an expression of array type to an expression of pointer type, if it's used in a context that wants a pointer.
You don't need to remember that, oh, it gets converted to a pointer "except" sizeof
, and &
, etc. You just have to think about the context of the expression.
For example, consider when you try to pass an array expression to a function call. Function parameters cannot be of array type per the C standard. If the corresponding parameter is a pointer type (which it must be in order to compile), then the compiler sees that, oh, it wants a pointer, so it applies the array-expression-to-pointer-type conversion.
Or, if you use an array expression with the dereference operator *
, or arithmetic operators +
-
, or subscript operator, []
; these operators all operate on pointers, so again, the compiler sees that, and applies the conversion.
When you try to assign an array expression, well, in C, array types are not assignable, so the only way it could compile is if it's assigned to a pointer type, in which case, again, the compiler sees that it needs a pointer, and applies the conversion.
When you use it with sizeof
, and &
, those contexts make sense inherently for arrays, so the compiler doesn't bother to apply the conversion. The only reason that these are viewed as the "exception" to the array-to-pointer conversion, is simply that, all other expression contexts (as you can see in the examples above) in C do not make sense for array types (array types are so crippled in C), and these few are the only ones "left".
An expression of array type is implicitly converted to a pointer to the array object's first element unless it is:
&
operator;sizeof
; orAn examples of the third case are:
char arr[6] = "hello";
"hello"
is an array expression, of type char[6]
(5 plus 1 for the '\0'
terminator). It's not converted to an address; the full 6-byte value of of "hello"
is copied into the array object arr
.
On the other hand, in this:
char *ptr = "hello";
the array expression "hello"
"decays" to a pointer to the 'h'
, and that pointer value is used to initialize the pointer object ptr
. (It should really be const char *ptr
, but that's a side issue.)
An expression of function type (such as a function name) is implicitly converted to a pointer to the function unless it is:
&
operator; orsizeof
(sizeof function_name
is illegal, not the size of a pointer).That's it.
In both cases, no pointer object is created. The expression is converted to ("decays" to) a pointer value, also known as an address.
Note that both the array indexing operator []
and the function call "operator" ()
require a pointer. In an ordinary function call like func(42)
, the function name func
"decays" to a pointer-to-function, which is then used in the call. (This conversion needn't actually be performed in the generated code, as long as the function call does the right thing.)
The rule for functions has some odd consequences. The expression func
is, in most contexts, converted to a pointer to the function func
. In &func
, func
is not converted to a pointer, but &
yields the function's address, i.e., a pointer value. In *func
, func
is implicitly converted to a pointer, then *
dereferences it to yield the function itself, which is then (in most contexts) converted to a pointer. In ****func
, this happens repeatedly.
(A draft of the C11 standard says that there's another exception for arrays, namely when the array is the operand of the new _Alignof
operator. This is an error in the draft, corrected in the final published C11 standard; _Alignof
can only be applied to a parenthesized type name, not to an expression.)
The address of an array and the address of its first member:
int arr[10];
&arr; /* address of entire array */
&arr[0]; /* address of first element */
are the same memory address, but they're of different types. The former is the address of the entire array object, and is of type int(*)[10]
(pointer to array of 10 int
s); the latter is of type int*
. The two types are not compatible (you can't legally assign an int*
value to an int(*)[10]
object, for example), and pointer arithmetic behaves differently on them.
There's a separate rule that says that a declared function parameter of array or function type is adjusted at compile time (not converted) to a pointer parameter. For example:
void func(int arr[]);
is exactly equivalent to
void func(int *arr);
These rules (conversion of array expressions and adjustment of array parameters) combine to create a great deal of confusion regarding the relationship between arrays and pointers in C.
Section 6 of the comp.lang.c FAQ does an excellent job of explaining the details.
The definitive source for this is the ISO C standard. N1570 (1.6 MB PDF) is the latest draft of the 2011 standard; these conversions are specified in section 6.3.2.1, paragraphs 3 (arrays) and 4 (functions). That draft has the erroneous reference to _Alignof
, which doesn't actually apply.
Incidentally, the printf
calls in your example are strictly incorrect:
int fruits[10];
printf("Address IN constant pointer is %p\n",fruits);
printf("Address OF constant pointer is %p\n",&fruits);
The %p
format requires an argument of type void*
. If pointers of type int*
and int(*)[10]
have the same representation as void*
and are passed as arguments in the same way, as is the case for most implementations, it's likely to work, but it's not guaranteed. You should explicitly convert the pointers to void*
:
int fruits[10];
printf("Address IN constant pointer is %p\n", (void*)fruits);
printf("Address OF constant pointer is %p\n", (void*)&fruits);
So why is it done this way? The problem is that arrays are in a sense second-class citizens in C. You can't pass an array by value as an argument in a function call, and you can't return it as a function result. For arrays to be useful, you need to be able to operate on arrays of different lengths. Separate strlen
functions for char[1]
, for char[2]
, for char[3]
, and so forth (all of which are distinct types) would be impossibly unwieldy. So instead arrays are accessed and manipulated via pointers to their elements, with pointer arithmetic providing a way to traverse those elements.
If an array expression didn't decay to a pointer (in most contexts), then there wouldn't be much you could do with the result. And C was derived from earlier languages (BCPL and B) that didn't necessarily even distinguish between arrays and pointers.
Other languages are able to deal with arrays as first-class types but doing so requires extra features that wouldn't be "in the spirit of C", which continues to be a relatively low-level language.
I'm less sure about the rationale for treating functions this way. It's true that there are no values of function type, but the language could have required a function (rather than a pointer-to-function) as the prefix in a function call, requiring an explicit *
operator for an indirect call: (*funcptr)(arg)
. Being able to omit the *
is a convenience, but not a tremendous one. It's probably a combination of historical inertia and consistency with the treatment of arrays.
The description given in the linked page in the first part of your question is certainly completely incorrect. There is no pointer there, constant or not. You can find the exhaustive explanation of array/function behavior in @KeithThompson's answer.
On top of that it might make sense to add (as a side note) that arrays implemented as two-part objects - a named pointer pointing to an independent nameless block of memory - are not exactly chimerical. They existed in that specific form in the predecessor of C language - B language. And initially they were carried over from B to C completely unchanged. You can read about it in Dennis Ritchie's "The Development of the C Language" document (see the "Embryonic C" section).
However, as it is stated in that very document, this kind of array implementation was incompatible with some new features of C language, like struct types. Having two-part arrays inside struct objects would turn such objects into higher-level entities with non-trivial construction. It would also make them incompatible with raw-memory operations (like memcpy
and so on). Such considerations are the reason arrays were redesigned from two-part objects into their current single-part form. And, as you can read in that document, the redesign was performed with backward-compatibility with B-style arrays in mind.
So, firstly, this is why many people get confused by the behavior of C-style arrays, believing that there a pointer hidden in there somewhere. The behavior of the modern C array was specifically designed to emulate/sustain that illusion. And, secondly, some archaic document might still contain leftovers from that "embryonic" era (although, it does not look like the document you linked should be one of them.)