Categories
arrays c pointers

Is an array name a pointer?

247

Is an array’s name a pointer in C?
If not, what is the difference between an array’s name and a pointer variable?

7

  • 5

    No. But array is the same &array[0]

    – user166390

    Oct 29, 2009 at 6:51

  • 37

    @pst: &array[0] yields a pointer, not an array 😉

    – jalf

    Oct 29, 2009 at 6:55

  • 33

    @Nava (and pst): array and &array[0] are not really the same. Case in point: sizeof(array) and sizeof(&array[0]) give different results.

    Oct 29, 2009 at 7:50

  • 2

    @Thomas agree, but in terms of pointers, when you dereference array and &array[0], they produce the same value of array[0].i.e. *array == array[0]. Nobody meant that these two pointers are the same, but in this specific case (pointing to the first element) you can use the name of array either.

    Oct 29, 2009 at 11:12

  • 1

    These might also help in your understanding: stackoverflow.com/questions/381542 , stackoverflow.com/questions/660752

    – Dinah

    Oct 29, 2009 at 15:06

301

An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.

Here is an array:

int a[7];

a contains space for seven integers, and you can put a value in one of them with an assignment, like this:

a[3] = 9;

Here is a pointer:

int *p;

p doesn’t contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:

p = &a[0];

What can be confusing is that you can also write this:

p = a;

This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.

Now you can use p in a similar way to an array:

p[3] = 17;

The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).

For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)

So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.

18

  • 7

    A similar automatic conversion is applied to function pointers – both functionpointer() and (*functionpointer)() mean the same thing, strangely enough.

    Oct 29, 2009 at 6:52

  • 3

    He did not asked if arrays and pointers are the same, but if an array’s name is a pointer

    Oct 29, 2009 at 6:58

  • 36

    An array name is not a pointer. It’s an identifier for a variable of type array, which has an implicit conversion to pointer of element type.

    Oct 29, 2009 at 7:24

  • 32

    Also, apart from sizeof(), the other context in which there’s no array->pointer decay is operator & – in your example above, &a will be a pointer to an array of 7 int, not a pointer to a single int; that is, its type will be int(*)[7], which is not implicitly convertible to int*. This way, functions can actually take pointers to arrays of specific size, and enforce the restriction via the type system.

    Oct 29, 2009 at 7:25

  • 4

    @onmyway133, check here for a short explanation and further citations.

    Feb 12, 2015 at 15:39

46

When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.

int arr[7];

/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */

/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */

0

    30

    If an expression of array type (such as the array name) appears in a larger expression and it isn’t the operand of either the & or sizeof operators, then the type of the array expression is converted from “N-element array of T” to “pointer to T”, and the value of the expression is the address of the first element in the array.

    In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.

    Edit

    Answering the question in the comment:

    If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?

    When you create an array, the only space that’s allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given

    char a[10];
    

    what you get in memory is

       +---+
    a: |   | a[0]
       +---+ 
       |   | a[1]
       +---+
       |   | a[2]
       +---+
        ...
       +---+
       |   | a[9]
       +---+
    

    The expression a refers to the entire array, but there’s no object a separate from the array elements themselves. Thus, sizeof a gives you the size (in bytes) of the entire array. The expression &a gives you the address of the array, which is the same as the address of the first element. The difference between &a and &a[0] is the type of the result1char (*)[10] in the first case and char * in the second.

    Where things get weird is when you want to access individual elements – the expression a[i] is defined as the result of *(a + i) – given an address value a, offset i elements (not bytes) from that address and dereference the result.

    The problem is that a isn’t a pointer or an address – it’s the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn’t the operand of the sizeof or unary & operators, the type of that expression is converted (“decays”) to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).

    C was derived from an earlier language called B, and in B a was a separate pointer object from the array elements a[0], a[1], etc. Ritchie wanted to keep B’s array semantics, but he didn’t want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.

    Remember that I said arrays don’t store any metadata about their size. As soon as that array expression “decays” to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There’s no way to know based on the pointer itself.

    When you pass an array expression to a function, all the function receives is a pointer to the first element – it has no idea how big the array is (this is why the gets function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.


    1. Which *may* affect how the address value is interpreted – depends on the machine.

    12

    • Have been looking for quite a long time for this answer. Thank you! And if you know, could you tell a little further what an array expression is. If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?

      Dec 7, 2017 at 21:51

    • And one more thing. An array of length 5 is of type int[5]. So that is from where we know the length when we call sizeof(array) – from its type? And this means that arrays of different length are like different types of constants?

      Dec 9, 2017 at 13:09

    • @AndriyDmytruk: sizeof is an operator, and it evaluates to the number bytes in the operand (either an expression denoting an object, or a type name in parentheses). So, for an array, sizeof evaluates to the number of elements multiplied by the number of bytes in a single element. If an int is 4 bytes wide, then a 5-element array of int takes up 20 bytes.

      – John Bode

      Dec 9, 2017 at 23:40

    • Isn’t the operator [ ] special too? For example, int a[2][3];, then for x = a[1][2];, though it can be rewritten as x = *( *(a+1) + 2 );, here a isn’t converted to a pointer type int* (though if a is an argument of a function it should be converted to int*).

      – Stan

      Jun 21, 2018 at 17:17

    • 2

      @Stan: The expression a has type int [2][3], which “decays” to type int (*)[3]. The expression *(a + 1) has type int [3], which “decays” to int *. Thus, *(*(a + 1) + 2) will have type int. a points to the first 3-element array of int, a + 1 points to the second 3-element array of int, *(a + 1) is the second 3-element array of int, *(a + 1) + 2 points to the third element of the second array of int, so *(*(a + 1) + 2) is the third element of the second array of int. How that gets mapped to machine code is entirely up to the compiler.

      – John Bode

      Jun 21, 2018 at 21:03