Your understanding is correct; a char* does point to a single char.
The trick is that arrays are laid out contiguously in memory, so given a pointer to the first element of an array, you can access the other elements by simply adding an offset to the pointer.  In your example, things look (logically) like this:
+-----+
| ptr |
+--+--+
   |
   v
 +-+-+---+---+---+---+---+----+
 | s | t | r | i | n | g | \0 |
 +---+---+---+---+---+---+----+
ptr points at the 's' at the beginning of "string".  By adding 1 to ptr, you can find the 't', and so on.  That's what the (builtin) [] operator does.  ptr[2] is defined to be equvilent to *(ptr + 2): offset the pointer by 2 positions, and then fetch the value pointed to by the result.
A '\0' character is used to mark the end of the string, so that the consuming code knows to stop looking for more characters.