In programming, pointers are variables that hold memory addresses, which are often the addresses of other variables. Every object in memory has an address — where its content can change but not its address.
Some variations on pointers include unique pointers and borrowed pointers (or references).
In C and C++
In C/C++, we denote pointers with an asterisk. The de-reference operator (&
) explicitly spits out the memory address. In both of these languages, arrays also function as pointers.
C++ also adds std::unique_ptr
in the STL.
Pointer arithmetic
Oftentimes when we think about arrays as pointers, we observe that we can:
Note that the addition isn’t in terms of bytes! It’s in terms of sizeof(int)
.
Void pointers
Void pointers are meant to represent typeless memory. Once we know the type of the memory we need to use, we should cast it to that type.1
Void pointers are useful for dynamic memory allocation, since malloc and free()
returns void*
and we can cast it to any type we desire. For anything we do to void*
, like for a function input, we can do to any other pointer type.
The idea with de-referencing pointers is that we tell the compiler how far out in the memory to go. Void pointers have no size (as opposed to an integer pointer, which stores 4 bytes), so de-referencing gives us a compile-time error. In other words, we can’t do pointer arithmetic or use array notation on void*
because the compiler won’t be able to figure out what Assembly instructions to produce.
In Rust
Rust has several pointer mechanisms:
- Unique pointers
- Borrowed pointers (references)
- A few more esoteric ones that we can get to when we get to
In Assembly
Pointers occupy a full word of memory, since they represent an -bit address. A key mechanism to dereference data at pointer values is below (in Nios II). We first move the pointer address into a register, then we access the data stored at that address (de-reference).
Footnotes
-
From why do void* pointers even exist?, by Low Level Learning. ↩