const pointer and pointer to const value as parameter [duplicate] - c++

This question already has answers here:
What is the difference between const int*, const int * const, and int const *?
(23 answers)
Closed last year.
I have a program like below and expect that:
with function void myFunc1 ( const int *x) ==> I cannot change the value of at the memory location that x points to, but can change the memory location that x points to.
with function void myFunc2 ( int const *x) ==> I cannot change the location that x points to as it is a const pointer. But I could change the value at the memory location that x points to.
However, upon compiling the code, I don't see the difference between const int *x vs int const *x:
in both function, the lines *x=8 in both function return error. I didn't expect error from myFunc2 because it is a const pointer, not a pointer to a const value.
in myFunc1, I expected to see value 5 after myFunc1 is close.
Could the experts here explain my 2 unexpected results above ? Here is my code:
#include "stdio.h"
int a = 5; // declared a global,
void myFunc1 ( const int *x) { // const parameter: pointer to a const int value.
// *x= 8; // error: assignment of read-only location ‘* x’ ==> cannot change the value at the location pointed by pointer. This is expected
printf("%d \n ", *x);
x = &a; // can change where the pointer point to.
// a is global and is not loss after closing myFunc2
printf("value in myFunc1: %d \n ", *x);
}
void myFunc2 ( int const *x) { // const parameter: const pointer, cannot change the address that x points to.
// *x= 8; // error: assignment of read-only location ‘* x’
printf("%d \n ", *x);
x = &a; // no compiling error here. This is not expected.
printf("value in myFunc2: %d \n ", *x);
}
int main() {
int *y;
int z = 6;
y = &z;
printf("value before myFunc1: %d \n", *y);
myFunc1(y);
printf("value after myFunc1: %d \n", *y); // expect to print 5. Result: print 6.
printf("value before myFunc2: %d \n", *y);
myFunc2(y);
printf("value after myFunc2: %d \n", *y); // expect to print 8 if the line *x=8 could be compiled . Result: print 6.
return 1;
}

I don't see the different between having 2 parameters (const int *x) vs (int const *x):
That's because int const* and const int* are the same thing.
If you want to make the pointer const, you have to put a const on its right, like this: int * const, a constant pointer to (non-constant) integer.
Unrelated (is it?) note on East const
I am one of those in favour of the so called East const, which means I prefer writing the const always on the right of what it applies to. For instance,
for a "pointer to constant int", I write int const *,
for a "constant pointer to constant int", I write int const * const.
As you see, the sentences in quotes map to the types if you read them right-to-left:
// 1 2 3 4 4 3 2 1
int const * const // constant pointer to constant int
Furthermore, always thinking of const as something that can be put on the right of what it applies to has also other advantages, sometimes in terms of peculiarities of the language that you can discover.
For instance, the following is how I discovered something more about references.
Take the declaration of a function parameter taken by reference to constant: int const& p. If you write it like this and think of it the East const way, it is clear that it declaring a p which is a reference to a constant int, not a constant reference to int.
After all, thinking East const, what would a constant reference to int look like? It'd be int & const, with the const on the right of what we'd like it to apply to, the reference &. However, this syntax is incorrect.
Why is that? Why can't I make a reference constant? Because it always is, as references cannot rebind. The standard simply doesn't let you write something totally redundant as a const applied to a reference.

Related

What does `float* const* ` mean?

Take a look at this function signature:
AudioBlock (SampleType *const *channelData, size_t numberOfChannels, size_t startSampleIndex, size_t numberOfSamples)
from here
The main type used if float* so let's think of the signature as
AudioBlock (float *const *channelData, size_t numberOfChannels, size_t startSampleIndex, size_t numberOfSamples)
What does float *const *channelData mean? channelData should be a const pointer to a float pointer? What is a const* something? I don't see the type of the inner pointer.
Suppose I want to create a vector of zeros so I can pass to AudioBlock:
std::vector<float> v(bufferOriginal.getNumChannels()*bufferOriginal.getNumSamples(), 0);
How do I get a float *const *channelData to this vector data?
What does float* const* mean?
float is a fundamental floating point type. T* is a pointer to T. const is a qualifier that applies to whatever is on the left side of it (except when it is the left most token in which case it applies to right). Since both qualifier and the pointer apply to left, it is easies to read from right to left (there are more complicated cases where this simplified rule of thumb is wrong):
float * const * // original
* const * float // reversed
* | const * | float // added spaces and separators
non-const pointer to | const pointer to | non-const float // translated to english
Arrays are an example of more complex cases where just right to left doesn't work. For the more complex rule that works with all compound types, see "clockwise rule" or "spiral rule".
So it's not possible to get a float* const * to the vector data then, right?
You could, if you had a vector like this:
std::vector<float*> vector_of_pointers;
float* const* ptr = vector_of_pointers.data();
You could make element of that vector point to your vector of floats.
vector_of_pointers.push_back(v.data());
This parameter declaration
float *const *channelData
means that the variable channelData (read from tight to left) is a pointer to a constant pointer (the pointer itself that is constant) to a non-constant object of the type float.
To make it more clear consider the following demonstrative program.
#include <stdio.h>
int main(void)
{
float x = 1.1f;
float y = 2.2f;
printf( "x = %f\n", x );
float * const px = &x;
// px = &y; // error: assignment of read-only variable ‘px’
*px = y;
printf( "x = %f\n", x );
float * const * ppx = &px;
// *ppx = &y; // error: assignment of read-only location ‘*ppx’
**ppx = 3.0f;
printf( "x = %f\n", x );
return 0;
}
Its output is
x = 1.100000
x = 2.200000
x = 3.000000
As you can see as the pointer px is a constant variable it has to be initialized when it is declared. You can not change it such a way that it will point to another variable. But you can use pc to change the value of the object pointed to by px. The variable ppx is a pointer to such a pointer.

What is the meaning of *&var? [duplicate]

I saw someone using this in one answer:
void methodA(const int*& var);
I couldn't understand what the argument means.
AFAIK:
const int var => const int value which can't be changed
const int* var => pointer to const int, ie *var can't be changed but var can be changed
const int& var => reference to const int, ie value of var can't be changed
What does const int*& var mean? Is const int& *var also possible?
Can you please give some example as well, like what can and can't be done with it?
UPDATE:
I am not sure if I am thinking the right way, but I began to think of a reference as an alias of the variable that was passed as argument, so:
const int * p;
methodA(p) => here we are passing p as const int * but we don't know if this is pass by value or what, until we see the definition of methodA, so if methodA is like this:
methodA(const int * & p2) ==> here p2 is another name to p, ie p and p2 are the same from now on
methodA(const int* p2) ==> here p2 is passed as value, ie p2 is just local to this method
Please correct me if I am thinking the wrong way. If yes, I might need to study some more about this. Can you please point to some nice references?
UPDATE 2:
If some beginner like me wants to know more about this thing, you can use the c++decl / cdecl program from here, which I just discovered to be very useful.
$ c++decl
Type `help' or `?' for help
c++decl> explain const int&* p
declare p as pointer to reference to const int
c++decl> explain const int*& p
declare p as reference to pointer to const int
But, as every one here pointed out, the first example isn't legal in C++.
It is a reference to a pointer to an int that is const.
There is another post somewhat related, actually, here. My answer gives a sorta of general algorithm to figuring these things out.
This: const int& *var has no meaning, because you cannot have a pointer to reference.
If the const's and pointers are getting in the way, remember you can typedef these things:
typedef int* IntPointer;
typedef const IntPointer ConstIntPointer;
void foo(ConstIntPointer&); // pass by reference
void bar(const ConstIntPointer&); // pass by const reference
void baz(ConstIntPointer); // pass by value
Might make it easier to read.
If you need more help on C++, read this. More specifically, references.
References as variables do not take space:
int i; // takes sizeof(int)
int*pi = &i; // takes sizeof(int*)
int& ri = i; // takes no space.
// any operations done to ri
// are simply done to i
References as parameters use pointers to achieve the end effect:
void foo(int& i)
{
i = 12;
}
void foo_transformed(int *i)
{
*i = 12;
}
int main()
{
int i;
foo(i); // same as:
foo_transformed(&i); // to the compiler (only sort of)
}
So it's actually passing the address of i on the stack, so takes sizeof(int*) space on the stack. But don't start thinking about references as pointers. They are not the same.
Some folks find it easier reading this from right to left. So
const int*&
is a reference to a pointer to an integer that is const.
As you know, references cannot be changed, only what they refer to can be changed. So the reference will refer to just one pointer to an integer that is const. Since the pointer is not const - the integer is const - you can change the pointer to point to a different integer.
Compare this to
int* const &
This is a reference to a constant pointer to an integer. Again the reference is immutable, and in this case it is a reference to a constant pointer. What you can change in this case is the integer value since there was no const either side of the int keyword.
Just to add confusion, const int and int const are the same. However int const * and int * const are very different. The first is a pointer to a constant integer, so the pointer is mutable. The second is a constant pointer to an integer, so the integer is mutable.
Hope this helps!
In your example, var is a refernce to a pointer to const char.
Since it's a reference, a change to the parameter inside methodA() will be reflected in the argument that is passed to methodA():
void methodA( const char*& var)
{
static const char newdata[] = {'a', 'b', 'c', '\0'};
printf( "var points to %s\n", var);
var = newdata;
}
int main()
{
const char * p = "123";
printf( "p points to: %s\n", p); // prints "p points to: 123"
methodA( p);
printf( "now p points to: %s\n", p); // prints "now p points to: abc"
}
It is a reference to a const pointer, i.e. a pointer where you cannot modify the data pointed to. As the reference is used as an argument to a method the method is able to modify the pointer to let it point to something else (still something that cannot be modified).
With regards to your update:
so if methodA is like this methodA(const int * & p2) ==> here p2 is another name to p, i.e. p and p2 are same from now on and if methodA(const int* p2) ==> here p2 is passed as value i.e p2 is just local to this method
Yes, you are correct.
Here's another example, a getter that returns the address of a private data item. The item happens to be an int for simplicity. A large array of items would be a more practical case (a zero-copy getter).
#include <iostream>
using namespace std;
class X {
public:
void getter(const int *&data) const
{
data = &val;
}
private:
int val = 5;
};
main()
{
X obj;
const int *data;
obj.getter(data);
cout << data << endl;
cout << *data << endl;
}

Playing with reference variables and pointers

Is int &y=x same as int y=&x?
Are s++ and *s++ the same?
Also in the below code, why is *s++ giving me some wrong results?
I was expecting *s value to be 12
#include <iostream>
using namespace std;
int main()
{
int p=10;
int &q=p; //q is a reference variable to p
//int r=&p; //error: invalid conversion from 'int*' to 'int'
int *s=&p; //valid
q++;
*s++; //here even s++ works, and cout<<*s does not give 12 but some lengthy number
//and cout<<s gives some hexadecimal, I'm guessing thats the address
cout<<p<<endl<<q<<endl<<*s;
}
Output I'm getting:
11
11
6422280
int &y=x same as int y=&x.
In first y is an integer reference which is initialized to x . OTOH, in second you are trying to assign int a value of int * which results in a compilation error .
why is *s++ giving me some wrong results? I was expecting *s value to be 12
This is because ++ has precedence over * , therefore ,first s is incremented first (thus pointing to uninitialized memory location), and then dereferenced .
Which is leading to dereference of uninitialized memory location resulting in undefined behaviour.
If you want to expected value , you can do this -
(*s)++; //dereference first and then increment
Is int &y=x same as int y=&x?
No. They are very different.
int x;
int& y = x; // y is a reference to x.
On the other hand,
int x;
int y = &x; // Should be compiler error.
// Initializing y with a pointer.
The line:
*s++;
is equivalent to:
int* temp = s;
s++;
*temp;
You are evaluating *temp but the side effect is that you are incrementing s. After that s points to the next element. That is not a valid address though. The next time you access *s, the program exhibits undefined behavior. The output of the line:
cout<<p<<endl<<q<<endl<<*s;
can be anything.
Is int &y=x same as int int y=&x?
Not nearly. The first binds the x to the int-reference y, the second initializes the int y with the address of x.
Both can be made to compile cleanly, but the second only with severe contortions abusing operator overloading:
{
int y;
int& x = y;
}
{
// Only for demonstration, never do something this crazy for real
struct { int operator&() { return 0; }; } x;
int y = &x;
}
Are s++ and *s++ the same?
Certainly not, though they have the same effect in your example, as you discard the result:
The first increments s and returns its pre-increment value.
The second does the same, but then dereferences that.
In both cases, s thereafter points behind an object, and may not be dereferenced on pain of Undefined Behavior (UB).
Which explains the curious number you got, but might also have resulted in your program just printing 42 and then beginning to reformat your harddrive (legal but unlikely).

why can we increment the dereferenced pointer to a constant data in C++?

I was surprised that c++ allows incrementing dereferenced pointer to a constant data, which it should not allow through a pointer to a const data. Consider the code:
#include<iostream>
#include<climits>
using namespace std;
int main(){
int x = 2;
const int *xPtr2 = &x;
*xPtr2++;
cout << x << endl;
}
But still the value of x is 2. That means *xPtr2 was not actually incremented. I also tried *xPtr2 = 3, but this time it shows compilation error. Why is it so?
Here the precedence of ++ is more than that of *. Hence
*xPtr2++
is equivalent to
*(xPtr2++)
Since xPtr2 is not a constant pointer but a pointer to constant data, incrementing xPtr2 and dereferencing it is fine in this case (but not others) and hence no compilation error is caused.
The ++ operator has precedence over dereferencing. Basically you're dereferencing the pointer that has been incremented.
For the behavior you're trying to accomplish, you should wrap the pointer in parens.
(*xPtr2)++;
Same goes for assigning - you're trying to assign an int to a int *. It would work with parens.
(*xPtr2) = 3;
See your example in ideone.
You have mentioned
dereferencing pointer to constant data
So, lets consider the following code
#include <stdio.h>
int main() {
const int foo = 0xdead;
int* bar = (int*) &foo;
*bar = 0xcafe;
printf("const int foo = %#x", foo);
return 0;
}
Output : const int foo = 0xcafe
In C, C++ const is just a compile time modifier for variables. This means that the compiler wants no modification to a const at compile time. At runtime there is no concept of const => all local variables are stored in stack, all static and global variables are stored in .data section. Thus you can dereference a const and modify it only at runtime

non-const pointer argument to a const double pointer parameter

The const modifier in C++ before star means that using this pointer the value pointed at cannot be changed, while the pointer itself can be made to point something else. In the below
void justloadme(const int **ptr)
{
*ptr = new int[5];
}
int main()
{
int *ptr = NULL;
justloadme(&ptr);
}
justloadme function should not be allowed to edit the integer values (if any) pointed by the passed param, while it can edit the int* value (since the const is not after the first star), but still why do I get a compiler error in both GCC and VC++?
GCC: error: invalid conversion from int** to const int**
VC++: error C2664: 'justloadme' : cannot convert parameter 1 from 'int **' to 'const int **'. Conversion loses qualifiers
Why does it say that the conversion loses qualifiers? Isn't it gaining the const qualifier? Moreover, isn't it similar to strlen(const char*) where we pass a non-const char*
As most times, the compiler is right and intuition wrong. The problem is that if that particular assignment was allowed you could break const-correctness in your program:
const int constant = 10;
int *modifier = 0;
const int ** const_breaker = &modifier; // [*] this is equivalent to your code
*const_breaker = & constant; // no problem, const_breaker points to
// pointer to a constant integer, but...
// we are actually doing: modifer = &constant!!!
*modifier = 5; // ouch!! we are modifying a constant!!!
The line marked with [*] is the culprit for that violation, and is disallowed for that particular reason. The language allows adding const to the last level but not the first:
int * const * correct = &modifier; // ok, this does not break correctness of the code