Are arrays pointers?

New C/C++ programmers often have this confusion that all arrays are pointers. Well… they’re kinda, sorta, but not really. Let’s consider the following code:

Try compiling the code snippets using Coding Ground.

The pointer p points to the first character of arr. Remember that the index operator ([]) is automatically converted to addition then dereference.

Note: 2[p] would be evaluated to *(2 + p) giving us the same result as p[2]. It’s bad practice to use that form even if it works.

And dereferencing arr is similar to getting the first element

So when do arrays and pointers differ?

Pointers are variables. Meaning they have a location (address) and a value, which is the address of another variable. An array is a finite set of variables of the same type, contiguously located in memory.

Let’s try printing their actual values. I’m expecting addresses which are treated as long integers.

The outputs of these 2 are the same – the location of the first element of arr. Since they both yield the same address, the following lines would produce the same result as well.

Let’s try printing their addresses.

And this is where the difference begins. Since p is a pointer, hence a variable, it has an address. Arrays are not really variables by themselves but a container of variables. Using the array, with just its name, gives the address of the array. Getting the address of the array is a special treatment.

Arrays are closer to Functions than you expect. Simply using the name would result to the location of the array/function. Getting the address, using the address-of (&) operator, would produce the same result.

There’s another difference: size. Consider the following code:

If arrays are pointers, shouldn’t these 2 lines be equal? Unfortunately, arrays are not pointers.

Calling sizeof(p) is the same as sizeof(char *) or simply the size of a pointer. This is OS-dependent; it’s equal to 4 for 32-bit OS or 8 for 64-bit OS. Calling sizeof(arr) is the same as sizeof(char [5]), which is similar to 5 * sizeof(char). Which means, if we were to divide sizeof(arr) by sizeof(char), it would yield 5 or the number of elements in the array.

How is this possible?

The macro function sizeof() is evaluated during compile-time. Meaning, its value should be computed during compilation and replaced by the evaluated constant. All variables must be declared by compile-time. You can’t have a new variable during run-time. Since arrays are containers of variables, then arrays should also be known during compile-time. Arrays are required to be declared with the element type and its size.

Note: You might argue that you can create variables during run-time by memory allocation. Technically, this is not creating new variables, rather, you’re requesting for additional space. How that space is used is dependent on your code. Also, to use this requested memory space, you must have a pointer which is declared in compile-time.

Pointers are dynamic. They can change in the middle of a program. They can point to garbage initially, then to null in another point in time, then to requested space, etc. Hence, they cannot be evaluated during compile-time.

Array Decay

Let’s recap! Pointers are variables: they have an address and a value. Arrays are containers of variables: they have an address, multiple values, and the size is known during compile-time. You can loosely think of arrays as const pointers with a fixed size.

A const pointer is a pointer that cannot be assigned. Meaning, wherever it is pointing at the beginning of your program is where it’ll be pointing until the program ends.

What if I wanted to use arrays as a parameter for functions? Let’s say you wanted to have the following:

Then you call the function like so:

It’s going to work since our function assumes that a is an array of 5 characters and we pass it arr, which is an array of 5 characters. But what if I have another array of characters but with a different size? You might be thinking of doing something like this:

Then calling it like below; expecting all the characters to be printed out.

This will compile but it will not work as you may intend. In fact, you’ll notice that it will consistently print only the first 4 (for 32-bit OS) or 8 (for 64-bit OS) characters only. Sounds familiar? It is because arr here is not an array. Instead, it’s a pointer.

When declaring a parameter of a function to be an array, with or without a size, it is automatically degenerated to a pointer. Meaning, char arr[5] or char arr[] would be converted to char *arr. The size in the parameter is completely ignored. That’s just how C/C++ has decided to do it.

When calling the function and supplying the pointer parameter with an array, we say that the array has decayed to a pointer. Meaning, it has lost its size. Inside the function, the compiler has no idea how big arr is and treats it as a pointer.

Since we lost the size, simply add it as another parameter.

And call it with the size.

This is the more common practice when dealing with Arrays as function parameters.

Summary

Arrays are not pointers. Arrays can be loosely treated as const pointers with fixed size.