What exactly is the relationship between pointers and arrays in C++?


Like, why is it that sometimes, when a function input is supposed to be a pointer, you can use an array instead?

In: 0

Arrays are pointers.

RAM/memory consists of a bunch of “cells” where you can put bytes. Each cell has its own address, and the CPU retrieves this memory by sending the address to the RAM and waiting for a response.

Pointers are of course these memory addresses.

Arrays are consecutively stored elements in memory, and the program merely keeps track of the address of the first element, then adds to this address as it necessary to query the array. That is if the beginning of the array has address 5, I can query the second element of the array by querying address 5+1 = 6.

The way this actually works of course in C is by arrays simply being pointers. Doing arr[i] is equivelent to doing *(arr + i)

An array object is a pointer to a serialized list of objects. So if a function takes a pointer, it can take an “array,” because you aren’t passing the array, just the pointer to the array.

C++ has two types of arrays – C arrays, defined using *type variable_name[length]*, and C++ arrays, defined using the classes *std::array* or *std::vector*.

Arrays are always, somewhere inside, a contiguous chunk of memory filled with items of uniform width. In C++ arrays, that memory is managed by the *std::array* or *std::vector* objects, so you can just ask for some element, or request the array be resized, and the object takes care of it for you.

C arrays are extremely barebones. The variable *variable_name* is actually a pointer to the beginning of the array. When you want to access an element of the array, the only way to do with with C arrays is to take the pointer to the start of the array, increment it by *sizeof(type) * index*, and then access the element at that incremented pointer.

So if you have *int arr[5]*, that creates 20 contiguous bytes in memory, logically separated in 4-byte chunks, and *arr* is a pointer to the beginning of that memory. When you access it using *arr[2]*, the language will take the pointer *arr*, calculate the offset *sizeof(int) * 2 = 4 * 2 = 8*, and give you back the integer that is located 8 bytes away from *arr*.

(Note: the statement *int arr[5];* specifically creates this array on the stack, which sits between all the other things on the stack, and will be deleted when the function is done. If you need an array that can be resized, or that can last after this function is complete, you will need to allocate memory using *new*, and put that pointer into a regular old *int * arr*. You can still access array elements using *arr[index]*, but now the language won’t be able to tell you when you’re looking at an index that’s actually outside of your array.)

Internally, the objects *std::array* and *std::vector* are doing something similar. They will allocate a contiguous chunk of memory, and when you ask for an element, they do this same pointer arithmetic to find you that element.