The biggest thing you can do with them is called polymorphism. I can't explain that fully because it is a very confusing concept that you will only learn after playing with the code a lot. Here is how it works:
class BaseClass {};
class SubClass : pulbic BaseClass {}
class OtherSubClass : public BaseClass {}
BaseClass * Pointer = new SubClass;
BaseClass * OtherPointer = new OtherSubClass;
This way you can hold different data types in the same array using the base class as it's type.
Another reason is to pass an array. Instead of copying the entire array through the parameter which takes up a huge amount of time and memory, you can just pass in the first element in the array as a pointer and then increment through the array with the pointer. This way you only pass in 1 element of the array.
Another reason is because some datatypes only allow you to store the variable or object as a pointer so you can't change it. When you change the pointer, it only effects the pointer no the data it is pointed to. This is true for a lot of the DirectX objects to create 3D games.
Another reason is that you want to create dynamic memory instead of just declaring every possible instance of the data type you need to store the variable. An example of this is creating dynamic arrays that you can change the size of during run time.
I use pointers very often and almost in every program. I use them because they are in most cases less memory intensive than actual data types and objects. You will use them very often in game programming when you have to make copies of 3D models/textures instead of making multiple instances of that 3D model/texture which would take up very valuable computer processes time and memory.