Pointer-to-const and const-pointer - c++

It is written in one book that we cannot change the memory refered by pointer to const like:-
int a = 0, b = 2;
const int* pA = &a; // pointer-to-const. `a` can't be changed through this
int* const pB = &a; // const pointer. `a` can be changed, but this pointer can't.
const int* const pC = &a; // const pointer-to-const.
//Error: Cannot assign to a const reference
*pA = b;
pA = &b;
*pB = b;
Then i written a code to check this and there i had declared pointer to const but changed its memory location and it got run but it should give error ->
#include <iostream>
int main()
{
int a=12;
const int* ptr;
ptr = &a;
std::cout<<*ptr<<"\n";
std::cout<<ptr<<"\n";
std::cout<<*ptr<<"\n";
int b=20;
ptr=&b;
std::cout<<*ptr;
return 0;
}

First let's understand what is the meaning of
const int *p;
The line above means that p is a pointer to a const integer. It means that p is holding the address of a variable which is of 'const int' type. This simply means that you can change the value of pointer 'p'. But the variable whose address 'p' is holding can't be changed because it is of const int type. Now, if you do
int* const p;
it means that the pointer now is of const type and is holding the address of an integer variable. So, here the pointer can't be changed but the value of the variable it is pointing to can be.

Read the comment from the code again:
const int* pA = &a; // pointer-to-const. `a` can't be changed through this
It doesn't say that the pointer cannot be changed. It is the pointed object that cannot be changed (through the pointer). a is the object being pointed by pA.
i had declared pointer to const but changed its memory location and it got run but it should give error
It shouldn't "give" error. You can change a 'pointer to const' i.e. you can make it point to another object. What you couldn't change is a const pointer. But your pointer isn't const.

If you are expecting your code should give error; change prt declaration to -
int* const ptr;
Refer this link it will help you understand in more details Clockwise/Spiral Rule

Related

Why can't I assign value of pointer to const int to a pointer of int? [duplicate]

This question already has answers here:
const pointer assign to a pointer
(1 answer)
C++ - can't assign top-const pointer to another non-const pointer
(2 answers)
Assigning const int to a const pointer to int is illegal?
(2 answers)
Closed 2 years ago.
[Note: I saw another question asking about the same section in the same book, but for different reasons]Reading through the C++ primer book and was going through the section "top-level consts". Here it writes that:
The distinction between top-level and low-level matters when we copy an object.
When we copy an object, top-level consts are ignored
When we copy an object,
both objects must have the same low-level const qualification...
This I understood but I went ahead and manipulated an example given in the book multiple times to further my understanding with different scenarios. The code below is one such scenario:
int i = 5;
int *p = &i;
const int *const ptr = p;
p = ptr;
I had hypothesised before I ran the program that, Line 4 would be legal. However, intellisense instead threw me this error:
A value of type "const int *" cannot be assigned to an entity of type "int *"
Now I've done other things like *p = *ptr (which was legal), ptr = p (which would obviously be illegal) and changed the object i to const (which would henceforth require me to change p and satisfy the condition that copying an object must have the same low-level const). And in all cases, I've understood why.
But not for this scenario. Can someone explain why this is illegal?
First consider this example:
void foo(const int* p) {
*x = 1; // Error ! x is pointer to const
}
int x = 42;
foo(&x);
x is not const. Nevertheless, inside foo you are not allowed to modify its value via the const int* p, because it is a pointer to a const int. Having a pointer to const int does not imply that the int pointed to is actually const. It only means: You are not allowed to modify the int via that pointer.
The compiler does not consider what pointer you actually pass to see that *x = 1; is not allowed inside foo.
An int * on the other hand, does allow to modify the pointed to int. Now consider this:
const int x = 42;
const int* p = &x;
int* p2 = p; // Error ! why?
*p2 = 0; // <- because of this
If you were allowed to assign the const int* to a int* this would create a hole in const correctness, because a int* does allow you to modify the pointee.
The top level const in
const int* const p3 = &x;
refers to the pointer itself. You cannot modify the pointer. While you can modify this one:
const int* p4;
p4 = &x;

Const reference vs pointer to const

Why using pointer to const I can change value of variable the pointer points to while using const reference I cannot?
int a = 10;
int * const ptr = &a;
(*ptr)++; // OK
const int & ref = a;
ref++; // error
In the first example, you have a const pointer to a non-const int. This is, because const applies to the thing left of it, except there is nothing at the left side, then it applies to the right thing. Therefore, it's OK to increment the value, but it would be forbidden to increment the pointer (increment without dereferencing). In the second example, you try to increment a const reference, which is not allowed.
"const int *ptr" means that the data pointed to by the pointer is constant and cannot be changed while the pointer itself can change.
"int * const ptr" means that the pointer cannot point somewhere else while the data pointed to can change.
So your first increment works while the second one gives an error.
for fully understanding read the following ::
const int value = 5; // value is const
int *ptr = &value; // compile error: cannot convert const int* to int*
*ptr = 6; // change value to 6
The above snippet won’t compile -- we can’t set a non-const pointer to a const variable. This makes sense: a const variable is one whose value can not be changed. Hypothetically, if we could set a non-const pointer to a const value, then we would be able to dereference the non-const pointer and change the value. That would violate the intention of const.
2-Pointer to const value
A pointer to a const value is a (non-const) pointer that points to a constant value.
To declare a pointer to a const value, use the const keyword before the data type:
const int value = 5;
const int *ptr = &value; // this is okay, ptr is a non-const pointer that is pointing to a "const int"
*ptr = 6; // not allowed, we can't change a const value
In the above example, ptr points to a const int.
So far, so good, right? Now consider the following example:
1
2
int value = 5; // value is not constant
const int *ptr = &value; // this is still okay
A pointer to a constant variable can point to a non-constant variable (such as variable value in the example above). Think of it this way: a pointer to a constant variable treats the variable as constant when it is accessed through the pointer, regardless of whether the variable was initially defined as const or not.
Thus, the following is okay:
int value = 5;
const int *ptr = &value; // ptr points to a "const int"
value = 6; // the value is non-const when accessed through a non-const identifier
But the following is not:
int value = 5;
const int *ptr = &value; // ptr points to a "const int"
*ptr = 6; // ptr treats its value as const, so changing the value through ptr is not legal
Because a pointer to a const value is not const itself (it just points to a const value), the pointer can be redirected to point at other values:
int value1 = 5;
const int *ptr = &value1; // ptr points to a const int
int value2 = 6;
ptr = &value2; // okay, ptr now points at some other const int
3-Const pointers
We can also make a pointer itself constant. A const pointer is a pointer whose value can not be changed after initialization
To declare a const pointer, use the const keyword between the asterisk and the pointer name:
int value = 5;
int *const ptr = &value;
Just like a normal const variable, a const pointer must be initialized to a value upon declaration. This means a const pointer will always point to the same address. In the above case, ptr will always point to the address of value (until ptr goes out of scope and is destroyed).
int value1 = 5;
int value2 = 6;
int * const ptr = &value1; // okay, the const pointer is initialized to the address of value1
ptr = &value2; // not okay, once initialized, a const pointer can not be changed.
However, because the value being pointed to is still non-const, it is possible to change the value being pointed to via dereferencing the const pointer:
int value = 5;
int *const ptr = &value; // ptr will always point to value
*ptr = 6; // allowed, since ptr points to a non-const int
4-Const pointer to a const value
Finally, it is possible to declare a const pointer to a const value by using the const keyword both before the type and before the variable name:
int value = 5;
const int *const ptr = &value;
A const pointer to a const value can not be set to point to another address, nor can the value it is pointing to be changed through the pointer.
Recapping
To summarize, you only need to remember 4 rules, and they are pretty logical:
A non-const pointer can be redirected to point to other addresses.
A const pointer always points to the same address, and this address can not be changed.
A pointer to a non-const value can change the value it is pointing to. These can not point to a const value.
A pointer to a const value treats the value as const (even if it is not), and thus can not change the value it is pointing to.
Keeping the declaration syntax straight can be challenging. Just remember that the
int value = 5;
const int *ptr1 = &value; // ptr1 points to a "const int", so this is a pointer to a const value.
int *const ptr2 = &value; // ptr2 points to an "int", so this is a const pointer to a non-const value.
const int *const ptr3 = &value; // ptr3 points to a "const int", so this is a const pointer to a const value.
Conclusion
Pointers to const values are primarily used in function parameters (for example, when passing an array to a function) to help ensure the function doesn’t inadvertently change the passed in argument. We will discuss this further in the section on functions.
resource :: learncpp
There is a difference between a const pointer and a pointer to a const variable, depending on where you put the const qualifier:
int main()
{
int a = 10;
int* const ptr1 = &a;
(*ptr1)++; // OK - This is a const pointer to a non-const int
const int* ptr2 = &a;
(*ptr2)++; // Error - but THIS is a pointer to a const int
return 0;
}

Why can't a const pointer be set afterwards?

I know this is probably a trivial question. What is the logic behind not being able to set a const pointer after its declaration? It's not as if allocating memory will change the starting address which is what the const refers to. So why can't this...
int* const p;
p = new int [10];
... be done... which also prohibits the passing of a const pointer into a function?
This is the entire purpose of const.
const stands for "constant", and means the object cannot be assigned to.
If you want the pointer to be a variable, don't make it const.
I suspect you were expecting your assignment to be allowed because it was the first ever assignment to that object. You were wrong! This is the purpose of initialisation, which you are not presently using.
I'm guessing you meant to write:
int* const p = new int[10];
But I worry that you have more fundamental misconceptions here. For example:
It's not as if allocating memory will change the starting address
Yes, it absolutely, completely will.
When your p comes into existence, it has an unspecified value. Its value is not a "starting address" that you can use.
Then you assign to it (though you ought to have initialised instead). It takes on the value equals to the pointer returned by new. That pointer has no relationship to anything previous in your code.
Allocating memory does change the address. For instance if we have
int * foo;
foo = new int[bar];
foo is uninitialized and has a garbage value. Then foo = new int[bar]; assigns to foo a new address that is the start of a block of bar ints.
Now when you have
int* const p;
The pointer is const so we cannot change it after it is initialized.
Short version
The way you are defining the pointer means that it is const for itself, so you cannot reassign it and you have actually to assign it along with its declaration.
Here more details about the const keyword, even though it is not specifically oriented to the use with the pointers.
Please even note that the following code should not compile for you are not assigning a value to the const pointer p:
int main() {
int * const p;
}
The same is true for the following one:
int main() {
int const i;
}
It doesn't depend on the fact that you are dealing with a pointer, instead it's how the const keyword actually works and should/can be used.
More details about const and pointers
Anyway, I didn't see your whole code and it looks to me that your intent is not to have a const pointer, instead in your case it could help having a pointer to const (but it mainly depends on your problem, so I can be wrong).
How to define them depends on your purposes, of course.
You can either define it as a const pointer or a pointer to a const value, the means of which are slightly different (of course, you can also define a pointer as a const pointer to a const value, that is an easily deducible consequence of the others above mentioned).
The first one indicates that the pointer itself cannot be reassigned, thus you have to assign it during the declaration and that's all.
The second one instead define a pointer that is reassignable, but you can assign it only addresses of const variables of the given type (or better, even if they are defined as non const, they will be treated as const when accessed through that pointer, with all the limitations of the case).
It follows a brief example of the types of const pointer and pointer to const above mentioned:
int main() {
int i;
// pointer to const int
int const *icp;
// const pointer to int
int * const cip = &i;
// const pointer to const int
int const * const cicp = &i;
// this one can be reassigned, of course
icp = &i;
}
Note also that int const and const int are interchangeable, so the declarations below are equivalent:
int const *p;
const int *p;
Obviously, this is not an exhaustive list. I've only tried to give you more details about how the const keyword can be used while defining a pointer and which are the intended means of those declarations.
int* const p;
declares p to be a pointer which cannot be changed, i.e. you cannot change where it points to once it is initialized. However, you can change the values it points to since the object type it points to is int.
int* const p = new int [10];
p = new int[20]; // Not OK
p[0] = 100; // OK
Contrast that with
int const* p = new int [10];
p = new int[20]; // OK. You can change where the pointer points to.
p[0] = 100; // Not OK. You cannot change the value of what p points to.

pointer to const and const pointer to something

what is the difference between
const int d=1;
const int *p = &d;
and
const int d=1;
int const *p = &d;
What can I do with the former and the latter ?
There is no difference, they're completely identical.
The grammar of the language simply allows a certain amount of freedom for certain constructions, and CV-qualification of types is one of those situations. There are other examples (e.g. declarations like foo typedef int;).
const int *p;
The declaration above declares a pointer p that points to a constant int. In other words, you can't change the value of the referand but you can change p itself.
int* const p;
The declaration above declares a constant pointer p that points to an int. In other words, you can change the value of the referand, but you can't change p. Also,
const int d = 1;
int * const p = &d;
is not legal. Taking the address of d yields const int*, and coversion from const int* to int* is not allowed (you could inadvertedly change the value of a constant object if it were).
You could make the conversion explicitly by using const_cast:
const int d = 1;
int * const p = const_cast<int*>(&d);
but it would still be illegal (undefined behaviour) to change the value of d through p.
const int *p;
p is a pointer to a constant integer. You can change the value stored in p (thus it point somewhere else) but you can't change the value where p points to.
int* const p;
p is a constant pointer to a non constant integer. You can't change the value of p, but change the integer where it points to

Use a const int* const pointer to point to an int

I don't understand something here. In the following code I have defined an integer and a constant integer.
I can have a constant pointer (int* const) point to an integer. See the fourth line of code.
The same constant pointer (int* const) can not point to a constant integer. See the fifth line.
A constant pointer to a const (const int* const) can point to a constant integer. That's what I would expect.
However, the same (const int* const) pointer is allowed to point to a non constant integer. See the last line. Why or how is this possible?
int const constVar = 42;
int variable = 11;
int* const constPointer1 = &variable;
int* const constPointer2 = &constVar; // not allowed
const int* const constPointer3 = &constVar; // perfectly ok
const int* const constPointer4 = &variable; // also ok, but why?
int const constVar = 42; // this defines a top-level constant
int variable = 11;
int *const constPointer1 = &variable;
int *const constPointer2 = &constVar; // not allowed because you can change constant using it
const int *const constPointer3 = &constVar; // perfectly ok. here you can't change constVar by any mean. it is a low level constant.
const int *const constPointer4 = &variable; // also ok, because it says you can't change the value using this pointer . but you can change value like variable=15 .
*constPointer4=5; //you get error assignment of readonly location.because that pointer is constant and pointing to read only memory location.
You can always decide not to modify a non-const variable.
const int* const constPointer4 = &variable;
Just parse the definition: constPointer4 is a const (i.e you can't change what it is pointing to anymore) pointer to a const int (i.e. variable). This means that you can't modify variable through constPointer4, even though you can modify variable by other means.
THe other way around (accessing a const variable through a non-const pointer), you would need a const_cast.
Why is a pointer to const useful? It allows you to have const member functions in classes where you can guarantee to users that that member function does not modify the object.
const has less access rights than non const, thats why it is allowed. You will not be able to change "variable" through the pointer but that is not breaking any rules.
variable = 4; //ok
*constPointer4 = 4; //not ok because its const
You use this "const pointer to non const variable" situation a lot when calling functions.
void f(const int * const i)
{
i=4; //not ok
}
f(&variable);
A pointer to a const object cannot be used to modify that object. It doesn't matter whether someone else can modify it; it just can't be done through that pointer.
int i; // modifiable
const int *cip = &i; // promises not to modify i
int *ip = &i; // can be used to modify i
*cip = 3; // Error
*ip = 3; // OK
Line # 4
int* const constPointer2 = &constVar;
Here it should not be allowed because int* const part of the "int* const constPointer2" means that the pointer is contant and then when you go ahead and assign it to &constVar