C Programming: What is the difference between an array and a pointer?
Why is a raven like a writing-desk? (Lewis Carroll)
This is a copy of an article I wrote a long time ago. I'm putting it here to give it a more permanent home. Sorry for being off topic again!
I'm glad you asked. The answer is surprisingly simple: almost everything. In other words, they have almost nothing in common. To understand why, we'll take a look at what they are and what operations they support.
An array is a fixed-length collection of objects, which are stored sequentially in memory. There are only three things you can do with an array:
sizeof- get its size
You can apply
sizeofto it. An array x of N elements of type T (
T x[N]) has the size
N * sizeof (T), which is what you should expect. For example, if
sizeof (int) == 2and
int arr;, then
sizeof arr == 10 == 5 * 2 == 5 * sizeof (int).
&- get its address
You can take its address with
&, which results in a pointer to the entire array.
- any other use - implicit pointer conversion
Any other use of an array results in a pointer to the first array element (the array "decays" to a pointer).
That's all. Yes, this means arrays don't provide direct access to their contents. More specifically, there is no array indexing operator.
A pointer is a value that refers to another object (or function). You might say it contains the object's address. Here are the operations that pointers support:
sizeof- get its size
Like arrays, pointers have a size that can be obtained with
sizeof. Note that different pointer types can have different sizes.
&- get its address
Assuming your pointer is an lvalue, you can take its address with
&. The result is a pointer to a pointer.
*- dereference it
Assuming the base type of your pointer isn't an incomplete type, you can dereference it; i.e., you can follow the pointer and get the object it refers to. Incomplete types include
structtypes that haven't been defined yet.
-- pointer arithmetic
If you have a pointer to an array element, you can add an integer amount to it. This amount can be negative, and
ptr - nis equivalent to
ptr + -n(and
-n + ptr, since
+is commutative, even with pointers). If
ptris a pointer to the
i'th element of an array, then
ptr + nis a pointer to the
(i + n)'th array element, unless
i + nis negative or greater than the number of array elements, in which case the results are undefined. If
i + nis equal to the number of elements, the result is a pointer that must not be dereferenced.
That's it, really. However, there are a few other pointer operations defined in terms of the above fundamental operations:
->- struct dereference
p->mis equivalent to
.is the struct/union member access operator. This means
pmust be a pointer to a struct or union.
- indexed dereference
a[b]is equivalent to
*(a + b). This means
bmust be a pointer to an array element and an integer; not necessarily respectively, because
a[b] == *(a + b) == *(b + a) == b[a]. Another important equivalence is
p == 0[p] == *p.
A quirk of parameter declarations
However, there's one thing that confuses this issue. Whenever you declare a function parameter to have an array type, it gets silently converted to a pointer and any size information is ignored. Thus the following four declarations are equivalent:
void foo(int ); void foo(int ); typedef int t_array; void foo(t_array); void foo(int *);
A more common example is
int main(int argc, char *argv), which is the same
int main(int argc, char **argv). However,
int main(int argc, char argv) would be an error because the above rule
isn't recursive; the result after conversion would be
int main(int argc, char (*argv)), i.e.
argv would be a pointer to an
array of unknown size, not a pointer to a pointer.
Arrays by themselves are nearly useless in C. Even the fundamental
operator, which is used for getting at the array's contents, is an illusion:
it's defined on pointers and only happens to work with arrays because of the
rule that any use of an array outside of
& yields a pointer.