The purpose of a pointer is to save the address of a specific variable. Then the memory structure of following code should look like:
int a = 5;
int *b = &a;
I think there should be no hierarchy if the address we are going to save refers variable, pointer, double pointer
Without the "hierarchy" it would be very easy to generate UB all over without any warnings - that would be horrible.
Consider this:
char c = 'a';
char* pc = &c;
char** ppc = &pc;
printf("%c\n", **ppc); // compiles ok and is valid
printf("%c\n", **pc); // error: invalid type argument of unary ‘*’
The compiler gives me an error and thereby it helps me to know that I have done something wrong and I can correct the bug.
But without "hierarchy", like:
char c = 'a';
char* pc = &c;
char* ppc = &pc;
printf("%c\n", **ppc); // compiles ok and is valid
printf("%c\n", **pc); // compiles ok but is invalid
The compiler can't give any error as there are no "hierarchy".
But when the line:
printf("%c\n", **pc);
executes, it is UB (undefined behavior).
First *pc
reads the char
as if it was a pointer, i.e. probably reads 4 or 8 bytes even though we only reserved 1 byte. That is UB.
If the program didn't crash due to the UB above but just returned some garbish value, the second step would be to dereference the garbish value. Once again UB.
Conclusion
The type system helps us to detect bugs by seeing int*, int**, int***, etc as different types.