One simple answer - read it backwards (as driven by Clockwise/Spiral Rule).
int * ptr
- ptr is a pointer to int
int const * ptr
- ptr is a pointer to constant int
int * const ptr
- ptr is a constant pointer to int
const int * const ptr
- ptr is a constant pointer to const int
Now the first const can be on either side of the type so:
const int * ptr
equal toint const * ptr
const int * const ptr
equal toint const * const ptr
If you want to go really crazy you can do things like this:
int ** ptr
- ptr is a pointer to pointer to intint ** const ptr
- ptr is a const pointer to a pointer to an intint * const * ptr
- ptr is a pointer to a const pointer to an intint const ** ptr
- ptr is a pointer to a pointer to a const intint * const * const ptr
- ptr a const pointer to a const pointer to an int- or anything else
And to make sure we are clear on the meaning of const
const int* ptr1;
int *const ptr2; //note, here you need to set the pointer here because you can't change it later
ptr1
is a variable pointer to a constant int. This lets you change what you point to but not the value that you point to. Most often this is seen with cstrings where you have a pointer to a const char
. You may change which string you point to but you can't change the content of these strings. This is important when the string itself is in the data segment of a program and shouldn't be changed.
ptr2
is a const or fixed pointer to a value that can be changed. This is like a reference without the extra syntactic sugar. Because of this fact, usually you would use a reference where you would use a T* const
pointer unless you need to allow null pointers.
How to discover whether 'const' applies to pointer or to pointed data: split the statement at asterix sign, then, if the const keyword appears in the left part (like in const int * foo
) - it belongs to pointed data, if it's in the right part (int * const bar
) - it's about the pointer.