The general procedure for reading a type in C/C++ is:
- Identify the final type, which can be a basic type or a typedef identifier, and which can have type modifiers such as const, volatile, etc. In your example that's "char".
- Apply the operators to the identifier in the same order of precedence as they have in expressions. These operators can be * (dereference), [] (index) and () (call function).
In the original philosophy of the syntax, your example would have been written "char *array[5]", the identifier is "array" and the operators are [] (index) then * (dereference).
The declaration then reads like a contract "if you apply these operators in that order, then you get an object of the final type".
In your case the full sentence is "if you index the variable "array", then dereference the resulting expression, you get a char".
You can also consider it like that "if you index the variable "array", then you get an object such that if you dereference it, you get a char"
The trick is mostly to keep track of the fact that [] and () have a higher precedence than *. You can control the operator order with parentheses just like for regular expressions.