confusion on constant pointer [duplicate] - c++

This question already has answers here:
What is the difference between const int*, const int * const, and int const *?
(23 answers)
Closed 5 years ago.
int p=10;
const int * ptr=&p; // expression 1
As far as i understood by expression 1 that the data which is pointed by pointer ptr is constant
so if i write
*ptr=10;
which is invalid ,
but if i take another pointer variable like
int * pr=&p;
*pr=19;
cout<<*ptr;
will give me the ouput 19
so now the data pointed by ptr changed
but earlier we have seen that data pointed by ptr is constant
why data is changed by another pointer variable?

const int * ptr=&p; means the data pointed to by ptr is const, but only relative to that pointer.
The pointed-to data is not necessarily really const (=originally declared const) and if it isn't, non-const pointers to it (including the original const-pointer cast to its non-const version) may change it.
If some data is really const, attempts to modify it through an non-const pointer result in undefined behavior.

This is very basic, so my suggestion is to read a basic C++ book.
Despite of that I'll provide the answer.
int p = 10;
It is a statement which declares and defines a variable named p of type int.
The content of this variable can be modified. That's because the variable p is not const.
Obviously the later statement p = 13; is still valid and it assigns a new value to that variable.
Now you have this:
const int* ptr = &p;
You're defining a pointer, named ptr which points to that variable.
Adding the qualifier const to the pointer it simply means that you cannot modify the content of the variable by means of the access of the pointer itself.
In other words, the pointer can be only used (for example) for reading the value of p.
On the other hand:
int* pr = &p;
defines a pointer which is not more const qualified.
Indeed, you can access and modify the content of the variable p by means of the usage of that pointer itself. (*pr = 19; is a valid statement).
A little bit far...
This is the general idea behind behind a "more complex world".
The statement:
const int* ptr = &p;
it's possible because the a variable can be implicitly converted in its const version.

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;

What is the difference between char * const and const char *? (Duplicate - Need more clarification)

So this is just a duplicate of:
What is the difference between char * const and const char *?
What's the difference between:
char * const
and
const char *
But I still do not get it.
So given the first answer:
The difference is that const char * is a pointer to a const char,
while char * const is a constant pointer to a char.
The first, the value being pointed to can't be changed but the pointer
can be. The second, the value being pointed at can change but the
pointer can't (similar to a reference).
Ok so, I have coded this to:
//exercises
char* barfoo = "variable_test";
const char* my_pointer_to_const_char = barfoo; //"barfoo" can't be changed but the pointer to it, can!
barfoo = "changed!";
std::cout<< barfoo << std::endl;
So according to the answer above, barfoo can't be changed?
I have changed it in my code, and it prints "changed". I don't understand shouldn't it be throwing an error ?
Can you please give me a correct example, because I am doing something wrong clearly.
You are missing two key concepts in your understanding.
A pointer, and the "thing" the pointer is pointing to. They are two separate, discrete "things". The pointer itself. And whatever the pointer is pointing to. That's the first key concept.
The second key concept is that either one, or the other, can be const. Or both can be const. Whatever's const, cannot be changed.
If the pointer itself is const, you can't change the pointer. It will always point to the same "thing", until the pointer goes out of scope and gets destroyed. But, even if the pointer is const, you can use this pointer to modify its "thing" unless the "thing" itself is const.
If the pointer is a pointer to a const "thing" you cannot change the "thing" using this pointer. But you can change the pointer to point to a different const "thing".
Or, even if the pointer is, allegedly, is a pointer to a const "thing", if there's another pointer that's pointing to the same "thing", and the other pointer may not necessarily be a pointer to a const "thing"; it could be a non-const pointer. In that situation, the other pointer can be used to change the same "thing" (because, after all, it is not a pointer to some const thing). And now, even though the first pointer is a pointer to const thing, the const thing it's pointing to has now changed. And this leads to an arcane discussion about aliasing rules that are better left for some other day...
But, back to the subject matter at hand:
char* barfoo = "variable_test";
const char* my_pointer_to_const_char = barfoo; //"barfoo" can't be changed but the pointer to it, can!
barfoo = "changed!";
Here, you changed one of the pointers, itself. You did not change whatever the pointer is pointing to. The literal string "variable_test" is still "there", wherever that "there" is, and the const pointer is still pointing to it. Whatever you do to one pointer, has no effect on the other pointer. They are different "thing"s.
You need to undergo a slight mental shift. You need to clearly separate, in your mind, the pointer itself, from whatever the pointer is pointing to.
We know that pointers store the address values of their operands.
As an example, if char *ptr=a, ptr will store the address of variable a.
And any variable defined as a constant cannot change its value.
If const int a=5, then any statement like a++ is invalid because this will alter the value of a which is prohibited.
Similarly if a pointer ptr points to variable a with declaration const int *ptr=a. Statements like ptr=b will be invalid because ptr cannot point to b as it is a constant pointer pointing to a.
Having understood that, there happen to be two combinations of constants and pointers.
TYPE 1: Pointer to a constant
const int a=5;
int* const ptr=a;
In this case, the variable is a constant whose value cannot be modified.
Suppose the memory address of a is 0x9978. Since, pointer stores address of variable, ptr=0x9978.
Analyse the following statements:-
a=6; //Invalid: Value of a cannot be changed
*ptr=9; //Invalid: *ptr refers to a and will change its value.
int b=t;
ptr=b;//Valid: ptr is not constant and can point anywhere
Hope this concept is clear now.
TYPE 2: Constant pointer
Here the pointer is constant. Once it is pointed to a variable, it cannot point to any other variable. It stores a constant address throughout its life time.
int a=7;
const int* ptr=a;
Here the value of ptr(0x9978) cannot be modified.
See the statements again:-
a=6; //Valid: Value of a can be changed
*ptr=9; //Valid: *ptr refers to a and its value can be altered.
int b=t;
ptr=b;//InValid: ptr is constant and cannot point anywhere else.
Thus, ptr cannot point to any other variable now.
Coming to your question, to understand better, consider char * not as a pointer but as a variable of string type(character buffer)!
char* barfoo = "variable_test"; //barfoo is a string storing 'variable_test'
const char* my_pointer_to_const_char = barfoo;
// This is type 2, constant pointer. Thus, my_pointer_to_const_char cannot
//point to any other variable and will always store the address of barfoo
barfoo = "changed!";
//this is perfectly valid as this statement will alter the value of string
//barfoo. my_pointer_to_const_char will still store the address of barfoo.
If there are still any doubts, feel free to comment:)

Return "int * const" from a function [duplicate]

This question already has answers here:
What is the difference between const int*, const int * const, and int const *?
(23 answers)
Closed 6 years ago.
In the code below, why the returned pointer p is allowed to change? If f instead returns "const int *", then the compiler will complain type mis-match error at line "int *p =f()". Why does it do the same for "int * const"?
btw: I know there are memory leaks in the code, but that has nothing to do with the question.
int * const f() {
return new int(23);
}
int main(){
int * p=f();
p= new int(35);
return 0;
}
Because what you are returning is a unmodifiable pointer - not the pointer to unmodifiable data.
Yes, the returned pointer is not modifable - but it will never be modified! You are modifying the different pointer, p - which just happen to have the same value as your unmodifiable (and unnamed) pointer which is now gone - this object is a temporary and forgotten as soon as the statement is completed.
This is why returning const-qualified simple types by value from functions has no sense and actually triggers a warning in some compilers.
*const is a constant pointer while const * is a pointer to constant. The latter is immutable value; you can of course assign this value to a variable, like you would write int x = 42;. The former points at an immutable object, so assigning this to a variable that is supposed to point at a mutable object would presumably violate that object's constness.
In the code below, why the returned pointer p is allowed to change?
Because the type of p is int *. Since the pointer is not const, it may be modified. If you want p to not be modifiable, then you must make it const: int * const p
If f instead returns "const int *", then the compiler will complain type mis-match error at line "int *p =f()"
Pointer-to-const is not convertible to pointer-to-non-const. Such conversion is not allowed by the language because it would break const correctness.
Why does it do the same for "int * const"?
I guess you mean to ask "Why does the compiler allow assigning int * const to a int * variable?"
Copying a const object to a non-const object does not break const-correctness. When p is non-const, it's OK to modify it and the const temporary returned by f remains unmodified through it's entire (short) lifetime.
Constness of a temporary is rarely meaningful, and so is returning a top-level const value.

C/C++ Constants [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
const int = int const?
What is the difference between these combination of keywords ?
const int*
int const*
int* const
Is it possible to modify the value of a constant by accessing its address using a pointer ?
const int*
int const*
Both declare an pointer to an constant type int. It means that the pointer can be made to point to(hold) any other address but any attempt to modify the constant integer data type will result in Undefined Behavior.
int* const
Declares an constant pointer to an int type. It means that the pointer cannot be assigned any new address it will always keep pointing to the same address, but the integer it points to can be changed.
Is it possible to modify the value of a constant by accessing its address using a pointer ?
Yes, it is possible but it leads to a ill formed program exhibiting an Undefined Behavior.
In general:
const T === T const
and
const T * === T const *
but
T * const
makes the pointer constant, but not necessarily the contents of T.
const T * const === T const * const
will make both the contents of T and the pointer itself constants.
As for changing the contents of a const: you shouldn't be able to, but the compiler/OS/CPU don't try too hard to stop you, so you get what is colloquially called “undefined behaviour,” which is a nice way of saying “random crashes on some systems”
const int* and int const* are both a pointer to a constant int. This means that the value pointed to can not be changed but the pointer itself can be.
The third example int *const is a constant pointer to an int. This means that the value can be changed but the pointer can not.
Yes you can change the value of the address by using a pointer but doing so is undefined behavior and should be avoided. C++ also offers a const_cast to remove the constness of a variable.
If you have any other questions related to the const keyword you should reference the const correctness section of the C++ FAQ.
The first two are a variable pointer to a const int. The pointer itself can be changed. Without casting away const, the int can't be changed through this pointer. (It may, however, be modifiable through non-const references.)
The last is a const pointer to a variable int. Without casting away const, the pointer itself can't be changed. The int can be changed through the pointer.
This may be helpful. This is another one that talks about breaking it apart so you can see which parts become const in various scenarios.
Const binds to the left.
Unless it is the left most clause then in binds right.
Just read right to left
const int* => (const int)* => "pointer" to "const int"
=> Pointer can change.
=> Can't change the value it points at (the int is const)
int const* => (int const)* => "pointer" to "const int"
=> As above
int* const => int (* const) => "const pointer" to "int"
=> Can't change the pointer (its const) it always points
=> at the same things.
=> You can change the value of the object it points at.

C++ Returning Pointers/References

I have a fairly good understanding of the dereferencing operator, the address of operator, and pointers in general.
I however get confused when I see stuff such as this:
int* returnA() {
int *j = &a;
return j;
}
int* returnB() {
return &b;
}
int& returnC() {
return c;
}
int& returnC2() {
int *d = &c;
return *d;
}
In returnA() I'm asking to return a pointer; just to clarify this works because j is a pointer?
In returnB() I'm asking to return a pointer; since a pointer points to an address, the reason why returnB() works is because I'm returning &b?
In returnC() I'm asking for an address of int to be returned. When I return c is the & operator automatically "appended" c?
In returnC2() I'm asking again for an address of int to be returned. Does *d work because pointers point to an address?
Assume a, b, c are initialized as integers as Global.
Can someone validate if I am correct with all four of my questions?
Although Peter answered your question, one thing that's clearly confusing you is the symbols * and &. The tough part about getting your head around these is that they both have two different meanings that have to do with indirection (even excluding the third meanings of * for multiplication and & for bitwise-and).
*, when used as part of a type
indicates that the type is a pointer:
int is a type, so int* is a
pointer-to-int type, and int** is a
pointer-to-pointer-to-int type.
& when used as part of a type indicates that the type is a reference. int is a type, so int& is a reference-to-int (there is no such thing as reference-to-reference). References and pointers are used for similar things, but they are quite different and not interchangable. A reference is best thought of as an alias, or alternate name, for an existing variable. If x is an int, then you can simply assign int& y = x to create a new name y for x. Afterwords, x and y can be used interchangeably to refer to the same integer. The two main implications of this are that references cannot be NULL (since there must be an original variable to reference), and that you don't need to use any special operator to get at the original value (because it's just an alternate name, not a pointer). References can also not be reassigned.
* when used as a unary operator performs an operation called dereference (which has nothing to do with reference types!). This operation is only meaningful on pointers. When you dereference a pointer, you get back what it points to. So, if p is a pointer-to-int, *p is the int being pointed to.
& when used as a unary operator performs an operation called address-of. That's pretty self-explanatory; if x is a variable, then &x is the address of x. The address of a variable can be assigned to a pointer to the type of that variable. So, if x is an int, then &x can be assigned to a pointer of type int*, and that pointer will point to x. E.g. if you assign int* p = &x, then *p can be used to retrieve the value of x.
So remember, the type suffix & is for references, and has nothing to do with the unary operatory &, which has to do with getting addresses for use with pointers. The two uses are completely unrelated. And * as a type suffix declares a pointer, while * as a unary operator performs an action on pointers.
In returnA() I'm asking to return a pointer; just to clarify this works because j is a pointer?
Yes, int *j = &a initializes j to point to a. Then you return the value of j, that is the address of a.
In returnB() I'm asking to return a pointer; since a pointer points to an address, the reason why returnB() works is because I'm returning &b?
Yes. Here the same thing happens as above, just in a single step. &b gives the address of b.
In returnC() I'm asking for an address of int to be returned. When I return c is the & operator automatically appended?
No, it is a reference to an int which is returned. A reference is not an address the same way as a pointer is - it is just an alternative name for a variable. Therefore you don't need to apply the & operator to get a reference of a variable.
In returnC2() I'm asking again for an address of int to be returned. Does *d work because pointers point to an address?
Again, it is a reference to an int which is returned. *d refers to the original variable c (whatever that may be), pointed to by c. And this can implicitly be turned into a reference, just as in returnC.
Pointers do not in general point to an address (although they can - e.g. int** is a pointer to pointer to int). Pointers are an address of something. When you declare the pointer like something*, that something is the thing your pointer points to. So in my above example, int** declares a pointer to an int*, which happens to be a pointer itself.
Tyler, that was very helpful explanation, I did some experiment using visual studio debugger to clarify this difference even further:-
int sample = 90;
int& alias = sample;
int* pointerToSample = &sample;
Name Address Type
&alias 0x0112fc1c {90} int *
&sample 0x0112fc1c {90} int *
pointerToSample 0x0112fc1c {90} int *
*pointerToSample 90 int
alias 90 int &
&pointerToSample 0x0112fc04 {0x0112fc1c {90}} int * *
Memory Layout
PointerToSample Sample/alias
_______________......____________________
0x0112fc1c | | 90 |
___________|___.....__|________|_______...
[0x0112fc04] ... [0x0112fc1c
In returnC() and returnC2() you are not asking to return the address.
Both these functions return references to objects.
A reference is not the address of anything it is an alternative name of something (this may mean the compiler may (or may not depending on situation) use an address to represent the object (alternatively it may also know to keep it in register)).
All you know that a reference points at a specific object.
While a reference itself is not an object just an alternative name.
All of your examples produce undefined run-time behavior. You are returning pointers or references to items that disappear after execution leaves the function.
Let me clarify:
int * returnA()
{
static int a; // The static keyword keeps the variable from disappearing.
int * j = 0; // Declare a pointer to an int and initialize to location 0.
j = &a; // j now points to a.
return j; // return the location of the static variable (evil).
}
In your function, the variable j is assigned to point to a's temporary location. Upon exit of your function the variable a disappears, but it's former location is returned via j. Since a no longer exists at the location pointed to by j, undefined behavior will happen with accessing *j.
Variables inside functions should not be modified via reference or pointer by other code. It can happen although it produces undefined behavior.
Being pedantic, the pointers returned should be declared as pointing to constant data. The references returned should be const:
const char * Hello()
{
static const char text[] = "Hello";
return text;
}
The above function returns a pointer to constant data. Other code can access (read) the static data but cannot be modified.
const unsigned int& Counter()
{
static unsigned int value = 0;
value = value + 1;
return value;
}
In the above function, the value is initialized to zero on the first entry. All next executions of this function cause value to be incremented by one. The function returns a reference to a constant value. This means that other functions can use the value (from afar) as if it was a variable (without having to dereference a pointer).
In my thinking, a pointer is used for an optional parameter or object. A reference is passed when the object must exist. Inside the function, a referenced parameter means that the value exists, however a pointer must be checked for null before dereferencing it. Also, with a reference, there is more guarantee that the target object is valid. A pointer could point to an invalid address (not null) and cause undefined behavior.
Semantically, references do act as addresses. However, syntactically, they are the compiler's job, not yours, and you can treat a reference as if it is the original object it points to, including binding other references to it and having them refer to the original object too. Say goodbye to pointer arithmetic in this case.
The downside of that is that you can't modify what they refer to - they are bound at construct time.