2
int x = 10;
int * const p = &x;
const int **p1 = &p;

Having some trouble understanding why this is illegal.

EDIT

Thank you for all the great answers. Here is my interpretation of the answers, feel free to disagree. So, the error is in the 3rd line. It implies that original integer is constant but does not imply that the pointer it points to is constant and therefore it is illegal because we could attempt to change the pointer 'p' through 'p1' which is not possible because that is a constant pointer. So to fix this the third line must be:

int * const *p1 = &p;

This works because it says that while the original integer is non-constant (mutable) the pointer it points to is constant and therefore it is a legal statement. So this is also legal:

const int * const *p1 = &p;

This says the same thing except it also says that you cant change the original integer because it is constant.

5 Answers5

5

Something you need to get used to with pointer declarations is that you need to try reading them right to left. What matters is what's on each side of the *

int * const p means p is a const pointer to a non-const int

const int **p1 means p1 is a non-const pointer to a non-const pointer to a const int

Your second declaration fails because it creates a non-const variable from a const one.

rdowell
  • 729
  • 4
  • 15
  • 3
    almost correct, according to your last sentence this shouldnt work: `const int x = 3; int y = x;` – 463035818_is_not_an_ai Jun 05 '18 at 19:19
  • I understand what you're saying but even this does not work and seems to follow that logic:`const int ci = 42; const int * const p3 = &ci; const int ** p = &p3;` – Pingu Gandhi Jun 05 '18 at 19:21
  • 3
    At the top level, it's a copy, so the const doesn't matter. Const that is "wrapped inside" a pointer or reference sticks. Taking the address of something const cannot be assigned to something that holds the address of something non-const, or you could end up changing the const value through just by looking at it through the non-const lens (without a cast.) – Chris Uzdavinis Jun 05 '18 at 19:24
  • @ChrisUzdavinis yes, thank you for clarifying where I failed to elaborate – rdowell Jun 05 '18 at 19:26
2

Initializes new mutable int x with literal 10, fine:

int x = 10;

Initializes new constant pointer to mutable int p with address of x, fine:

int * const p = &x;

Initializes new mutable pointer to mutable pointer to constant int with address of p, constraint violation due to stripping the const, and also due to adding the inner-most const:

const int **p1 = &p;
// Normally qualifiers go to the right of the type they qualify
// The inner-most qualifiers can be put before them though without introducing ambiguity

Read the full rules on cppreference.com or directly in the standard, they are a bit long.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
1

Declares 2 ints which are constant:

int const x1 = 3;
const int x2 = 3;

Declares a pointer whose data cannot be changed through the pointer:

const int *p = &someInt;

Declares a pointer who cannot be changed to point to something else:

int * const p = &someInt;

Link: const int = int const?

Kad
  • 542
  • 1
  • 5
  • 18
0

The compiler (here, gcc) tells you

invalid conversion from 'int* const*' to 'const int**' [-fpermissive]

And the reason is that

p1 is a pointer to (non-const) pointer to const int

while

p is a const pointer to int

If the assignment was legal, you could modify the const variable p through p1 (as the type of *p1 would be const int * -- pointer to const int).

drRobertz
  • 3,490
  • 1
  • 12
  • 23
0

In

int * const p = &x;

that means the address/reference is constant, since the const comes after * (as opposed to the target value being constant, in other words const before the *, in other words const int *p)

In

const int **p1 = &p;

that means, p1, which I'll call the "outer pointer" points to const int *, which is wrong, b.c. it should be pointing to an int *const as the previous expression states.

In other words, as the compiler puts it,

error: cannot initialize a variable of type 'const int **' with an rvalue of type 'int *const *'
const int **p1 = &p;
solstice333
  • 3,399
  • 1
  • 31
  • 28