By user188276

2009-10-29 06:38:05 8 Comments

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


@John Bode 2009-10-29 14:54:25

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.


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 result1 - char (*)[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.

@Andriy Dmytruk 2017-12-07 21:51:32

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

@Andriy Dmytruk 2017-12-09 13:09:04

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?

@John Bode 2017-12-09 23:40:48

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

@Stan 2018-06-21 17:17:51

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

@John Bode 2018-06-21 17:34:15

@Stan: The subscript operation a[i] is defined as *(a + i) - given a starting address a, find the address of the i'th object in the array, and dereference the result. If a is an expression of array type, it will be converted to a pointer before the addition is performed. Remember that in pointer arithmetic, a + 1 yields the address of the next object of the pointed to type, not the next byte. If a points to a 4-byte int, then a + 1 points to the next 4-byte int. If a points to a 128-byte struct, then a + 1 points to the next 128-byte struct.

@Stan 2018-06-21 18:02:08

Sorry I didn't express it clearly. Yes, your explanation can be consistent, but I just think it easily confusing and can't reflect the ASM operations. If I didn't misunderstand, for my very example int a[2][3]; and then x = *( *(a+1) + 2 );, we are indeed able to interpret that a is first converted to the pointer type int (*)[3] so that a+1 moves forward sizeof(int [3]), and then *(a+1) dereferences the pointer int (*)[3] to the pointer int*, and then in the whole *( *(a+1) + 2 ) the int* pointer *(a+1) moves 2*sizeof(int) forward and is dereferenced to an int.

@Stan 2018-06-21 18:17:34

... though the above explanation is semantically correct, there aren't two dereference operations in the actual machine code. So, it might not be a good explanation.

@John Bode 2018-06-21 21:03:10

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

@Stan 2018-06-22 03:00:33

@JohnBode thanks for the detailed reply! But not “entirely up to the compiler” because the standard currently requires “contiguous allocated” (6.2.5 Types) for arrays, and in de facto implementations, I haven’t seen any compiler uses two dereferences for that 2D array. I guess the advantage for the “standardized” (though not really) memory layout of array could help design flexible function interface, e.g. void f(int* matrix, int rowNum, int columnNum) can adapt 2D arrays with different sizes.

@Thomas Padron-McCarthy 2009-10-29 06:39:08

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.

@Carl Norum 2009-10-29 06:52:43

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

@Ricardo Amores 2009-10-29 06:58:01

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

@Pavel Minaev 2009-10-29 07:24:12

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.

@Pavel Minaev 2009-10-29 07:25:54

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.

@Thomas Padron-McCarthy 2009-10-29 07:41:10

@Pavel: Thanks for the comment about &. I knew there were other exceptions, but sizeof was the only one on top of my mind. I've changed "an exception" to "one exception", which I think indicates that there are other exceptions (but I'm no a native English speaker).

@Johannes Schaub - litb 2009-10-29 07:50:07

to be fair, asking for the difference of an array's name in expressions to the name of a pointer is not asking whether arrays are different from pointers. Example: In C++, a reference's name in expressions is the same as the referenced object's name in expressions. Still, a reference is not the same as the object it references. But instead, while evaluating, the reference type is replaced by the referenced type, and is an lvalue. In C, somewhat similar happens with arrays, just that this conversion doesn't always happen: Not in sizeof and address-of: These are operators not applied to values

@Johannes Schaub - litb 2009-10-29 07:53:53

Note that this automatic conversion doesn't happen in C++. In C++, it happens only when needed (for example when assigning to a pointer), whereas in C, the array to pointer conversion always happens if not within sizeof or address-of or initializing an array with a string literal.

@onmyway133 2015-02-12 07:17:48

@CarlNorum Interesting, do you have any document for it

@Carl Norum 2015-02-12 15:39:32

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

@M.M 2015-12-21 11:58:58

Another situation the conversion does not happen is when the array is the operand of ++ or --

@Thomas Padron-McCarthy 2015-12-21 17:13:55

@M.M: I'm not sure what you mean there? It's true that there will be no conversion when doing char a[7]; a++;, but that's because it's an error.

@Thomas Padron-McCarthy 2016-12-27 17:47:30

@SurajJain: To start with, what would a=something mean? Changing the content of the array? That's how normal (non-array) variables work in C, and how arrays work in many other languages, but the designers of C decided to make arrays a kind of second class citizens, so they can't be assigned directly in that way.

@Suraj Jain 2016-12-28 05:01:06

@ThomasPadron-McCarthy , ok Thanks , i have another thing to ask is this valid printf("%d" , a) ,?? I am asking this in reference to this question…

@Thomas Padron-McCarthy 2016-12-28 13:40:11

@SurajJain: No, in printf("%d" , a) you are telling printf that you are sending it an integer, but instead you are sending it a pointer (pointing to the first element in the array). You can do printf("%p" , (void*)a) to print the pointer.

@Suraj Jain 2016-12-28 13:59:54

oh, sorry i forget to include 'a' what mean is does printf("%d" , 'a') correct ? using %d for char , as char are default promoted to int , this answer says you cannot but other seem to say that you can , i am confused…

@Thomas Padron-McCarthy 2016-12-28 14:20:39

As far as I know, printf("%d" , 'a') is allowed, which would make that answer incorrect in that detail. 'a' will be promoted to integer, so that is not a problem. But sometimes there are rather surprising constraints on what the standard guarantees will work on all conforming platforms, and without further study I'm not going to promise anything.

@Palo 2015-11-08 14:53:08

I think this example sheds some light on the issue:

#include <stdio.h>
int main()
        int a[3] = {9, 10, 11};
        int **b = &a;

        printf("a == &a: %d\n", a == b);
        return 0;

It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:

a == &a: 1

oops :-)

So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:

p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
  int **b = &a;
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
  printf("a == &a: %d\n", a == b);

C++ refuses any such attempts with errors in compile-time.


This is what I meant to demonstrate:

#include <stdio.h>
int main()
    int a[3] = {9, 10, 11};
    void *c = a;

    void *b = &a;
    void *d = &c;

    printf("a == &a: %d\n", a == b);
    printf("c == &c: %d\n", c == d);
    return 0;

Even though c and a "point" to the same memory, you can obtain address of the c pointer, but you cannot obtain the address of the a pointer.

@Lundin 2018-03-01 10:10:47

"It compiles fine (with 2 warnings)". That's not fine. If you tell gcc to compile it as proper standard C by adding -std=c11 -pedantic-errors, you get a compiler error for writing invalid C code. The reason why is because you try to assign a int (*)[3] to a variable of int**, which are two types that have absolutely nothing to do with each other. So what this example is supposed to prove, I have no idea.

@Palo 2018-04-02 21:09:27

Thank you Lundin for your comment. You know there are many standards. I tried to clarify what I meant in the edit. The int ** type is not the point there, one should better use the void * for this.

@SAQIB SOHAIL BHATTI 2015-09-28 11:14:37

Array name is the address of 1st element of an array. So yes array name is a const pointer.

@Amitesh Ranjan 2014-12-01 17:59:12

The array name behaves like a pointer and points to the first element of the array. Example:

int a[]={1,2,3};
printf("%p\n",a);     //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0

Both the print statements will give exactly same output for a machine. In my system it gave:


@pmg 2009-10-29 09:03:44

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 */
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 */

@Grumdrig 2009-10-29 06:50:14

An array declared like this

int a[10];

allocates memory for 10 ints. You can't modify a but you can do pointer arithmetic with a.

A pointer like this allocates memory for just the pointer p:

int *p;

It doesn't allocate any ints. You can modify it:

p = a;

and use array subscripts as you can with a:

p[2] = 5;
a[2] = 5;    // same
*(p+2) = 5;  // same effect
*(a+2) = 5;  // same effect

@Mark Bessey 2009-10-29 06:59:30

Arrays are not always allocated on the stack. Yhat's an implementation detail that will vary from compiler to compiler. In most cases static or global arrays will be allocated from a different memory region than the stack. Arrays of const types may be allocated from yet another region of memory

@Lightness Races BY-SA 3.0 2011-05-30 21:01:29

I think Grumdrig meant to say "allocates 10 ints with automatic storage duration`.

@Ricardo Amores 2009-10-29 06:50:38

An array is a collection of secuential and contiguous elements in memory. In C an array's name is the index to the first element, and applying an offset you can access the rest of elements. An "index to the first element" is indeed a pointer to a memory direction.

The difference with pointer variables is that you cannot change the location the array's name is pointing to, so is similar to a const pointer (it's similar, not the same. See Mark's comment). But also that you don't need to dereference the array name to get the value if you use pointer aritmetic:

char array = "hello wordl";
char* ptr = array;

char c = array[2]; //array[2] holds the character 'l'
char *c1 = ptr[2]; //ptr[2] holds a memory direction that holds the character 'l'

So the answer is kinda 'yes'.

@Mark Bessey 2009-10-29 06:56:52

An array name is not the same as a const pointer. Given: int a[10]; int *p=a; sizeof(p) and sizeof(a) are not the same.

@Pavel Minaev 2009-10-29 07:28:01

There are other differences. In general, it's best to stick to the terminology used by the C Standard, which specifically calls it a "conversion". Quote: "Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined."

@Michael Buen 2009-10-29 07:29:10

The array name by itself yields a memory location, so you can treat the array name like a pointer:

int a[7];

a[0] = 1976;
a[1] = 1984;

printf("memory location of a: %p", a);

printf("value at memory location %p is %d", a, *a);

And other nifty stuff you can do to pointer (e.g. adding/substracting an offset), you can also do to an array:

printf("value at memory location %p is %d", a + 1, *(a + 1));

Language-wise, if C didn't expose the array as just some sort of "pointer"(pedantically it's just a memory location. It cannot point to arbitrary location in memory, nor can be controlled by the programmer). We always need to code this:

printf("value at memory location %p is %d", &a[1], a[1]);

Related Questions

Sponsored Content

94 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 6270281 View
  • 7831 Score
  • 94 Answer
  • Tags:   javascript arrays

39 Answered Questions

[SOLVED] For-each over an array in JavaScript?

50 Answered Questions

13 Answered Questions

[SOLVED] What is a smart pointer and when should I use one?

43 Answered Questions

[SOLVED] Loop through an array in JavaScript

39 Answered Questions

28 Answered Questions

34 Answered Questions

[SOLVED] Create ArrayList from array

30 Answered Questions

[SOLVED] How to append something to an array?

18 Answered Questions

[SOLVED] With arrays, why is it the case that a[5] == 5[a]?

Sponsored Content