I am very confused with c++ pointers and reference operators. My main confusion is the following (simple ) code:
#include <iostream>
using namespace std;
void changeInt(int &a)
{
a *= 3;
}
int main()
{
int n = 3;
changeInt(n);
cout << n << endl;
return 0;
}
Mainly, I am confused as to why changing the address (&a) changes the actual variable (n). When I first attempted this problem this was my code:
#include <iostream>
using namespace std;
void changeInt(int &a)
{
*a *= 3;
}
int main()
{
int n = 3;
changeInt(n);
cout << n << endl;
return 0;
}
But this gives me an error. Why is it that when I change the address it changes the variable, but when I change the value pointed by the address I get an error?
Your second example is not valid C++, you can only dereference a pointer (or an object whose type overload operator*, which is not your case).
Your first example pass the parameter by reference (int &a is not "the address of a", it is a reference to a), which is why a change to a really is a change to the object being passed by the function (in you case, n)
The ampersand (&) in that context means a reference, not the "address". E.g.:
int some_int;
int & a = some_int; // Declare 'a', a reference to 'some_int'
int * p = &some_int; // '&' in this context is "the address of" 'some_int'
A reference is equivalent to a pointer in many ways, but it behaves like a value type.
See this thread and the wikipedia entry to learn more.
The ampersand indicates that a variable is passed by reference to your function -- but inside the function the variable is treated as if it were passed by value. This is syntactic sugar, to make writing code that accepts references simpler to understand.
Related
This question already has answers here:
Does int * & has any real sense?
(6 answers)
Closed 1 year ago.
I had the understanding that in c++ & and * cancel each other i.e int *&p is essentially equal to p as its value at address of integer p.
Now is it valid to pass reference to a pointer in view of above i.e say i am trying to pass reference to a pointer as an argument in a function as below?
void func(int* &p)
Won't the above result in cancellation of * with & and will just be int p?
How correct is it if i try to pass reference to pointer of a class object on similar terms?
#include <iostream>
using namespace std;
int gobal_var = 42;
// function to change Reference to pointer value
void changeReferenceValue(int*& pp)
{
pp = &gobal_var;
}
int main()
{
int var = 23;
int* ptr_to_var = &var;
cout << "Passing a Reference to a pointer to function" << endl;
cout << "Before :" << *ptr_to_var << endl; // display 23
changeReferenceValue(ptr_to_var);
cout << "After :" << *ptr_to_var << endl; // display 42
return 0;
}
You are correct that the & address-of operator and the * indirection operator cancel each other out when used inside an expression.
However, when used inside a declaration, these operators have a very different meaning. Inside a declaration, * means "pointer" and & means "reference". Therefore, when used inside a declaration, they do not cancel each other out.
An object of type int*& is simply a reference to a pointer to an int.
I have a function that remove the const attribute of the int* and change the value of the variable it point to, but it doesn't work since I pass a variable and reference it in the formal reference?
This is my code:
#include <bits/stdc++.h>
#include <iostream>
#include <map>
using namespace std;
typedef unsigned char UINT8;
int ll(const int &r)
{
*(const_cast<int *>(&r)) = 5;
// cout<<const_cast<int*> (&r)<<endl;
//*(&r)=5;
cout << r << endl;
}
int main()
{
const int a = 1;
ll(a);
cout << a << endl;
}
I expected the value shown in the function to be the same as the one in main(), but it's different.
Attempt to modify const-qualified object a causes Undefined Behavior. Language allows to alter types and/or qualifiers of references using reinterpret_cast and/orconst_cast but it is always programmer's responsibility to ensure that the object being accessed through a reference really has appropriate type and qualifiers.
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
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
The code snippet is as follows
#include <iostream>
using namespace std;
int a(int m)
{
return ++m;
}
int b(int &m)
{
return ++m;
}
int c(int &m)
{
return ++m;
}
int main(void)
{
int p=0,q=0,r=0;
p+=a(b(p));
q+=b(a(q));
r+=a(c(r));
cout<<p<<q<<r;
return 0;
}
The error occurring is invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int' at q+=b(a(q)). How to go about the error so that this program prints a desired output
Timothy J Williams is one or both of the following things:
wrong;
teaching C++ as it pertains to Visual Studio only, without disclaiming it, which is ill-advised.
References cannot bind to temporaries. It is not allowed in C++. Visual Studio allows it as a non-standard extension, but that's it. Some people get confused and think that means it's valid C++. It's not.
You will have to store the results of function calls like b(1) into named variables before you pass them anywhere by reference.
int main()
{
int p = 0, q = 0, r = 0;
int result_of_b_p = b(p);
p += a(result_of_b_p);
int result_of_a_q = a(q);
q += b(result_of_a_q);
int result_of_c_r = c(r);
r += a(result_of_c_r);
std::cout << p << q << r << '\n';
}
I should also note that the cited code is confusing and appears to serve no purpose other than for contrived "test your knowledge" challenges. I'd pay not too much attention to this and instead learn C++ from a proper book. After all, Timothy Williams claims that the above program outputs 322; it doesn't.
You cannot pass by reference a constant.
To break down your code.
int a(int m){
return ++m;
}
This will return an int (constant, eg. 5)
Then in
int b(int &m){
return ++m;
}
You are now technically passing in an integer (constant) not a variable into B. You must pass B in as a variable.
Try exactly what you have but passing in
int x = a(your_number_here);
int z = b(x);
EDIT:
int main(void){
int p=0,q=0;
int x = 5;
p = a(x);
q = b(p);
cout << q << endl;
return 0;
}
Returns 7.
The error is a result of trying to call a function that takes a reference with a value. It would be like calling b with a value literal b(1). That can't work...
The function call is where you pass by reference. See below:
void foo (int* m)
{
(*m)++;
}
int main (void)
{
int a = 0;
foo (&a);
cout << a << endl; // prints 1
}
So here b(int& m) takes a reference to an integer. Think about it this way. A reference is a "safe pointer" for which the compiler automatically handles the dereferencing operations.
The return value of a(int m) is a temporary, i.e. it is a temporary value that goes out of scope as soon as the function returns and its value has been utilized in some way. So you can do x = a(15); and x will become a copy of the returned 16. This is what an r-value is. A sort of "temporary" (r because it is on the right side of the expression). So when you have a pointer to a temporary value it does not make sense in most cases. For example in the following code
int* return_local() {
int a = 10;
return &a;
}
This will give you a compiler warning. Because you don't want to bind a pointer to a value which will go out of scope. Similarly you don't want a reference to an object that will go out of scope as soon as the function has returned and its value has been utilized. That is why there is an error in your code. a(int m) returns an r-value and when you do b(a(q) you are trying to bind a reference to an r-value
Now there is something called an r-value reference which takes the form void some_func(int&& rvalue_reference) in syntax. The && means r-value reference not reference to reference. Look it up if you are interested.
It's not allowed to pass a r-value as a non-const reference argument. This happens in the line whereyou call the function b with a(q) as its argument, which is an r-value (an expression which is not a simple variable).
So you need to first call a and store itsvalue in a variable, and then pass this variable to b:
int main(void)
{
int p=0,q=0,r=0;
p+=a(b(p));
int t=a(q);
q+=b(t);
r+=a(c(r));
cout<<p<<q<<r;
return 0;
}
I had a simple question and was hoping for the underlying logic behind passing by reference.
Here's one code (let's call it Code1):
void fn(int& a)
{
a = 6;
}
int main()
{
int b = 5;
fn(b);
cout << b;
}
Here's another code (Code2):
void fn(int* ptr)
{
*ptr = 6;
}
int main()
{
int b = 5;
fn(&b);
cout << b;
}
And a pass by value code (Code 3):
void fn(int a)
{
a = 6;
}
int main()
{
int b = 5;
fn(b);
cout << b;
}
Here goes my question. Intuitively, I see that while passing by value (Code3), the values are copied ie a would just have taken/copied into itself the value of b. Thus, as a general rule, I see that value passed is just copied always to the called function (here fn). Even with the pointer code (ie Code2), the first line of Code 2 ensures that int *ptr = &a;
I don't understand how this would work in Code1. Saying that &a = b makes no sense. Is this an exception, or does this fit into a rule that is consistent with the cases discussed in the paragraph above?
Thanks!
In this function:
void fn(int &a) {
a=6;
}
the term "&a" does not mean "the address of the variable a". It means "a reference called a". Code 1 and Code 2 are effectively the same (but note that the function in Code 2 can be passed an invalid pointer, which is (almost) impossible for Code 1).
For most intents and purposes, a reference is just a pointer in disguise. Different syntax, same effect (mostly).
Conceptually, in your first case what happens is that the same variable has two labels: b, visible within the scope of main(); and a, visible within the scope of fn.
You don't have to worry about what the compiler does "behind the scenes" to implement this concept.
If you mentally promote the compiler's "behind the scenes" actions to actually being imagined principles of C++, e.g. "the reference is a pointer in disguise", then it leads you to get confused about what is actually a pretty simple concept: the ability to give multiple names to a variable.
It is nothing special being a function parameter; e.g. you could write in main():
int a;
int &c = a;
which is exactly equivalent to:
int c;
int &a = c;
In both cases there is an int variable with two labels, a and c.