A pointer can be re-assigned:
int x = 5;
int y = 6;
int *p;
p = &x;
p = &y;
*p = 10;
assert(x == 5);
assert(y == 10);
A reference cannot be re-bound, and must be bound at initialization:
int x = 5;
int y = 6;
int &q; // error
int &r = x;
A pointer variable has its own identity: a distinct, visible memory address that can be taken with the unary &
operator and a certain amount of space that can be measured with the sizeof
operator. Using those operators on a reference returns a value corresponding to whatever the reference is bound to; the reference’s own address and size are invisible. Since the reference assumes the identity of the original variable in this way, it is convenient to think of a reference as another name for the same variable.
int x = 0;
int &r = x;
int *p = &x;
int *p2 = &r;
assert(p == p2); // &x == &r
assert(&p != &p2);
You can have arbitrarily nested pointers to pointers offering extra levels of indirection. References only offer one level of indirection.
int x = 0;
int y = 0;
int *p = &x;
int *q = &y;
int **pp = &p;
**pp = 2;
pp = &q; // *pp is now q
**pp = 4;
assert(y == 4);
assert(x == 2);
A pointer can be assigned nullptr
, whereas a reference must be bound to an existing object. If you try hard enough, you can bind a reference to nullptr
, but this is undefined and will not behave consistently.
/* the code below is undefined; your compiler may optimise it
* differently, emit warnings, or outright refuse to compile it */
int &r = *static_cast<int *>(nullptr);
// prints "null" under GCC 10
std::cout
<< (&r != nullptr
? "not null" : "null")
<< std::endl;
bool f(int &r) { return &r != nullptr; }
// prints "not null" under GCC 10
std::cout
<< (f(*static_cast<int *>(nullptr))
? "not null" : "null")
<< std::endl;
You can, however, have a reference to a pointer whose value is nullptr
.
Pointers can iterate over an array; you can use ++
to go to the next item that a pointer is pointing to, and + 4
to go to the 5th element. This is no matter what size the object is that the pointer points to.
A pointer needs to be dereferenced with *
to access the memory location it points to, whereas a reference can be used directly. A pointer to a class/struct uses ->
to access its members whereas a reference uses a .
.
References cannot be put into an array, whereas pointers can be (Mentioned by user @litb)
Const references can be bound to temporaries. Pointers cannot (not without some indirection):
const int &x = int(12); // legal C++
int *y = &int(12); // illegal to take the address of a temporary.
This makes const &
more convenient to use in argument lists and so forth.
Best Solution
The C standard defines the
[]
operator as follows:a[b] == *(a + b)
Therefore
a[5]
will evaluate to:and
5[a]
will evaluate to:a
is a pointer to the first element of the array.a[5]
is the value that's 5 elements further froma
, which is the same as*(a + 5)
, and from elementary school math we know those are equal (addition is commutative).