19

1) Misconception :

  • Whenever an array is declared in C language, a pointer to the first element of the array is created (the name of the array) implicitly. (Is it? I don't think so!)

  • The first two lines of this page (though I am not sure about the correctness of the information) state the same.

    As we have seen, when we declare an array, a contiguous block of memory is allocated for the cells of the array and a pointer cell (of the appropriate type) is also allocated and initialized to point to the first cell of the array.

  • But when I output the address contained in that pointer and the address of that pointer, they turn out to be the same. So, I think a pointer is not created after all.

2) I picked this up from this question.

  • In most cases array names are converted to pointers.

Can anyone give a detailed explanation of WHEN the compiler decides to convert an array name into a pointer, and WHY?

PS: Please explain the same with functions. Also in this link, an example was given, saying that for a function int square(int,int), any of the square, &square, *square, **square refers to the same function pointer. Can you explain?

Edit : Code snippet

int fruits[10];
printf("Address IN constant pointer is %p\n",  fruits);
printf("Address OF constant pointer is %p\n", &fruits); 

Output :

Address IN constant pointer is 0xbff99ca8
Address OF constant pointer is 0xbff99ca8
Community
  • 1
  • 1
progammer
  • 1,951
  • 11
  • 28
  • 50
  • berhaps break that into 2 questions, the first part has been asked a million times in different forms. the second one is interesting though. – Grady Player Jul 06 '13 at 19:07
  • @GradyPlayer I thought that arrays and functions would be treated similarly by the compiler , in this aspect . So I made it into a single question . – progammer Jul 06 '13 at 19:09
  • 2
    [The values of `&array` and `array` are are really the same, but semantically both are different. One is address of an array of 10 chars while the other is is an address of a char](http://stackoverflow.com/questions/15177420/what-does-sizeofarr-returns/15177499#15177499) – Grijesh Chauhan Jul 06 '13 at 19:10
  • 1
    For function pointers: [Why do all these crazy function pointer definitions all work? What is really going on?](http://stackoverflow.com/questions/6893285/why-do-all-these-crazy-function-pointer-definitions-all-work-what-is-really-goi?lq=1) – Grijesh Chauhan Jul 06 '13 at 19:14
  • 2
    As I given first link: `fruits` type is `int[10]` and `&fruits` type is `int(*)[10]` Both address are same but symmetrically both are different first `fruits`: is address of first element where is second `&fruits`: is address of array of 10 elements, for example try to print address of next location by print `fruits+ 1` and `&fruits + 1` – Grijesh Chauhan Jul 06 '13 at 19:25
  • 1
    @GrijeshChauhan Thanks for the very useful links . I will look them up and reply soon . – progammer Jul 06 '13 at 19:26
  • You will likely find this [article](http://support.microsoft.com/kb/44463) useful on differentiating between the two. – sedavidw Jul 06 '13 at 19:11
  • @Appy Note: `fruits` type is `int[10]` that easily decay into `int*` as address of first element. – Grijesh Chauhan Jul 06 '13 at 19:32
  • @luserdroog: The section of the [faq](http://www.c-faq.com/) on "Arrays and Pointers" (section 6) is actually more relevant here than the section on pointers (section 4). – Keith Thompson Jul 06 '13 at 20:43
  • Ack. I (incorrectly) assumed. I'll try to give more precise links in future. thx – luser droog Jul 06 '13 at 20:55
  • 1
    I've pasted the quote from the Hawaii university site. The quote is horribly wrong; there is no separate 'pointer cell' allocated when you allocate an array. – Jonathan Leffler Jul 07 '13 at 00:17
  • for almost any questions C related, first have a look at the **[C-faq](http://c-faq.com)**, and for example **[the passage on pointers and arrays](http://c-faq.com/aryptr/)** (born from the time where Usenet's Newsgroups were the only place where top answerers were going, meaning all the knowledge had only 1 place to update information) – Olivier Dulac Jul 07 '13 at 04:18

4 Answers4

36

An expression of array type is implicitly converted to a pointer to the array object's first element unless it is:

  • The operand of the unary & operator;
  • The operand of sizeof; or
  • A string literal in an initializer used to initialize an array object.

An 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:

  • The operand of the unary & operator; or
  • The operand of sizeof (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.

(The "conversion" in both these cases isn't an ordinary type conversion like the one specified by a cast operator. It doesn't take the value of an operand and use it to compute the value of the result, as would happen for an int-to-float conversion. Rather an expression of array or function type is "converted" at compile time to an expression of pointer type. In my opinion the word "adjusted" would have been clearer than "converted".)

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 ints); 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.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • @KeithThompson Superb explanation ! Thanks a lot :) Can u give a small example line of code for this - "A string literal in an initializer used to initialize an array object" ? – progammer Jul 06 '13 at 19:40
  • @KeithThompson Why did you emphasize on "in most contexts" , in the explanation about functions ? Are there any exceptions ? – progammer Jul 06 '13 at 19:48
  • @Appy an example would be char s[] = ""; – Sabashan Ragavan Jul 06 '13 at 19:51
  • 1
    @Appy: There are two exceptional cases in which a function name is not converted to a pointer. I already listed them. I've also added an example of a string literal used to initialize an array object. – Keith Thompson Jul 06 '13 at 20:42
  • I disagree that the third case counts. The right side of an array initialization statement is not syntactically an expression. Only specific syntactic elements are allowed as the initializer, namely, a pair of braces with elements inside (which is not an expression either), or, in the case of character arrays, a string literal (which happens to be an valid expression in expression contexts, but that is not relevant). – newacct May 01 '14 at 09:03
  • All three cases are explicitly listed in the C standard; see the [N1570 draft](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) section 6.3.2.1 paragraph 3. And if you look at the grammar for initializers in section 6.7.9, you'll see that a string literal in an initializer *is* an expression, specifically an *assignment-expression* (restricted to that form because a comma operator isn't allowed at the top level). – Keith Thompson May 01 '14 at 14:57
2

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.

Community
  • 1
  • 1
Sabashan Ragavan
  • 728
  • 1
  • 5
  • 14
2

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.)

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2

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".

newacct
  • 119,665
  • 29
  • 163
  • 224