A pointer is a distinct value, independent of the data it points to. (The number 0x12345678 is meaningful as a pointer value even if there's no meaningful data at address 0x12345678 in memory.) Because it's a distinct value, it can be manipulated on its own: you can increment or decrement it, compare it against other pointers, and print its value to the screen, regardless of whether it actually "points to anything."
You can't do any of those things with a reference because it's not a distinct value. It's an alias, an alternate name (possibly in a different scope) for some existing value. This makes references easier to use (since they act just like the object they refer to, no dereferencing needed), and also safer (since, if used properly, they always refer to an object; there's no such thing as a dangling or null reference).
It may be true that references typically get translated into pointers in the compiled machine code, but you should think of that as a private implementation detail of the compiler, not a guarantee. References are their own concept with their own use-cases, not just a different way of working with pointers.
When you need a distinct pointer-like value that you can manipulate and examine independently of the data it points to, use a pointer (or, preferably, a smart-pointer class). When you just need a way to take a value that exists in one scope and make it available in another scope (e.g. passing an object into a function without copying it), use a reference.