I thought pointers just held the memory address?
Yes, but you're allowed to do things with that memory address. In particular C++ allows something called 'pointer arithmetic' which allows you to use a memory address to obtain the address of other memory located relative to the memory you already have the address for. E.g., if you have a memory address you can get the address of the memory located immediately after it.
(the squares are memory locations)
☐
☐
☐ ← I have the address of this memory in variable A
☐ ← I would like to get the address of this memory location and to store it in X
☐
☐
☐
int *A = ...;
int *X = A + 1; // compute the address of the next memory location
So an array is a series of memory locations. To access any element of the array you simply take the address you have, compute the address of the element you want to access, and then use that new address.
int *A = new int[10];
int *X = A + 5; // get the address of the memory five locations past where A points to
*X = 999;
You don't have to store the address you compute in a variable:
int *A = new int[10];
*(A+5) = 999;
C++ provides a shorthand for the syntax *(A+5), this is the array index operator:
int *A = new int[10];
A[5] = 999;
One thing that's interesting is that the array index operator really is just shorthand for this *(A+5) expression. Since you can flip around the operands and do *(5+A) you can do the same with the array index operator:
5[A] = 999;
You shouldn't do that though, because it's not very readable.
Another thing to know about pointers: Java has pointers. When you do
String s = new String();
in Java s is a pointer. Java just tries to hide this fact at the same time that it requires the use of pointers to a much greater extent than C++ does. Java doesn't have pointer arithmetic, and you don't have to manually dereference pointers in Java like you have to in C++. But consider:
List<String> l = new List<String>();
List<String> m = l; // Do I have two lists, l and m, that can be modified independently? Or do I have two entities, l and m, that both refer to the same List object?
And remember those Null Pointer exceptions you get in Java.
If you've been using Java then you've already been using pointers. They're not really all that different in C++, but they're directly visible and explicit in C++ instead of being poorly hidden the way Java has them.