Pointers are easy and fun, just keep experimenting with them.
What is essential is understanding that they're nothing more than like a piece of paper containing
where something is instead of being part of that something, and they're the same size of the address registers of the underlying hardware as they must be able to point everywhere in the addressable memory. Therefore, on a 32 bit system pointers will be 32 bits long, on a 64 bit system they will be 64 bits long, etc. no matter what they point to.
That is, both a pointer to a single byte and a pointer to a 10GB memory chunk will be of the same size because they just hold a memory location whose value represents where that data starts.
Therefore, declaring pointers to a certain type doesn't change their size at all, it just becomes handy when one needs to go back and forth in a memory area in which objects of that type are stored one after another, so that incrementing or decrementing the pointer by a number actually means that number times the size of the objects. Imagine asking for directions to someone and he replies "3rd door" or "3rd building" or "3rd block"; he gave you a pointer that is always the same size, but how much you have to walk will depend on the destination (size).
Once grasped the above, it should become a lot more easy; I had the same problems, then one day had a flash and they became totally clear (and fun).
It may be of help experimenting with a debugger, or simply printf-ing all values a pointer assumes when declared, assigned, incremented/decremented etc. Keep also track of the pointed data values, changing it instead of the pointer, or the other way around, are common mistakes.
An old small command line program like "cdecl" can help a lot to understand complex declarations, and someone has even made an interactive webpage around it (cdecl.org).
example:
cdecl> explain char ((x())[]) ()
declare x as function returning pointer to array of pointer to function returning char