I think that understanding the concept of a pointer is much more important than the syntactical means of declaring and accessing a pointer. I think that the complexity of pointers is overblown to the point that they become intimidating and people try to get away with the most minimal understanding possible.
All a pointer is is a place to store a memory address. Everything else is implementation details. There are pointers in assembly in every architecture I've seen (admittedly few). Sometimes you need a lot of data available to a lot of functions, and it simply isn't acceptable to have copies of all of this data on the stack. A pointer gives you an easy way to store the memory address of this data so you can easily find it, and when you want another function to have access to it you just need to push 4 or 8 bytes onto the stack.
The only thing that C introduces is allowing you to determine what type of data is on the "other end" of your pointer. You don't have to do this, you can have a void * that points to an indeterminate type of data that you can later case to whatever type you need. However, since C is strongly typed, when you dereference a pointer it needs to know what type this evaluates to. C also uses pointers to deal with arrays. All an array is is a pointer to the first element, or base, of the list of values. Whenever you give an index into an array, the base address is added to sizeof(type)*index and this is the memory address for the element you've requested.
The C libraries dealing with character arrays use a special assumption of null termination to allow you do simply have a pointer to the start of a character array, with no additional information, to indicate a string. The libraries determine the end of the string when a null byte is reached. Without this convention more information would need to be known about the string, such as it's current length, maximum length, etc. I don't think it would have been awful for these things to be built-in, but one might argue that this is beyond language specification and really the job of a library to implement.
Once you wrap your head around what a pointer is for (which you may have already), then it's just a matter of syntax. The operators that come to mind immediately that deal with pointers in C are:
& - Unary. Get the address/pointer to the operand
* - Unary. Get the value pointed to by the operand
[] - Binary. The first operand is a pointer, the second an index. Take the value of the first operand, add the second times the size of the type of the first operand, and get the value at this memory address.
-> - Binary. This was discussed in my previous post. The left operand is a pointer to a struct, the right operand is the name of a field of this struct. Take the memory address pointed to by the left operand, add the offset of the field specified by the second operand in the struct, and return the value at this memory address (with the type determined by the struct definition).
That's pretty much it. I think a key to understanding all of this is to learn a bit about computer architecture, so you have some idea about memory and how data is shuffled around between it and registers, etc. It's not strictly necessary, but I think it helps a lot.
Really, it all boils down to the idea that a pointer is a variable that holds a memory address. The address itself is the value of a pointer. The value at the memory address the pointer contains isn't the pointer's value, as this memory can be changed without the value of the pointer being modified.
-Lee