Playing with reference variables and pointers - c++

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).

Related

Function calling at the left side of the expression

Can we have a function calling at the left side of the expression?
This code snippet works well but how? How can a function calling can be at left side and please elaborate how this snippet is executing and working well and what if i wouldn't have used static int in function definition.Thanks in advance.
#include<iostream>
using namespace std;
int &fun()
{
static int x;
return x;
}
int main()
{
fun() = 10;
/* this line prints 10 on screen */
printf(" %d ", fun());
getchar();
return 0;
}
Any expression that returns a non-const lvalue can be on the left side of the assignment and function call is also an expression like any other. Since lvalue historically means exactly that - value on the left side this turns into a recursive definition. So instead you can consider an lvalue anything that you can take address of:
int x = 5;
&x; //valid, takes the address of the variable
&5; //invalid, integer literal has no address
int func1();
&func1(); //invalid, can't take the address of the temporary value
int &func2();
&func2(); //valid, since the function returned reference
//which itself is almost the same as the address
So any expression that results in something addressable can be assigned to. You can even do something like this:
int x = 0;
int y = 0;
int z = 5;
(z > 5 ? x : y) = 10;
As for your second question, if you remove static from your function you would return a reference to a local variable of the function. Local variables stop existing when the function exits, so you would return a reference to a variable that is already destroyed. This, however, will compile and run, but the results of that execution would be unpredictable that's why this is called undefined behavior.

C++ pointers: dereferencing, assigning values, etc

The questions I'm asking are very basic, but I'm trying to understand the behaviour of pointers in C++ by doing exercises in the compiler. So, for example, I start by declaring an int pointer *p and trying to ascribe it some values and print it:
#include <iostream>
using namespace std;
int *p, i;
int main(){
i=5;
p=&i;
cout<<*p<<endl;
return 0;
}
This is very clear and easy, right? But while I'm wondering why the C++ syntax works this way, I test another way of assigning a value to a pointer:
#include <iostream>
using namespace std;
int *p, i;
int main(){
i=5;
p=&i;
*p=3;
cout<<*p<<endl;
return 0;
}
Obviously, the result is different now. The question is, why this wouldn't work:
#include <iostream>
using namespace std;
int *p, i;
int main(){
*p=3;
i=5;
p=&i;
cout<<*p<<endl;
return 0;
}
Why do I have to dereference the pointer first before assigning it a value, but direct assignment would not work without dereferencing?
Also, if in the second example I wrote I added another assignment:
int main(){
i=5;
p=&i;
*p=3;
*p=6;
cout<<*p<<endl;
return 0;
}
This would not change the value stored at *p (it would still be 3). I don't simply want to learn by memorising this pointer behaviour, I'm interested in understanding why it works this way. Thanks.
#include <iostream>
using namespace std;
int *p, i;
int main(){
*p=3;
i=5;
p=&i;
cout<<*p<<endl;
return 0;
}
This doesn't work because you are trying to assign a value to the integer that p points to. That's what this line does:
*p = 3;
That means, "store the value 3 at the location which p points at". But p doesn't point at anything, because you didn't assign it to point to anything until two lines later.
p = &i;
That means, "assign the address of i to be the value of p". Or, in other words, "store the address of i in p". p needs to point to something, before you can assign to the thing p points to. Otherwise you have undefined behavior.
On the last section:
int main(){
i=5;
p=&i;
*p=3;
*p=6;
cout<<*p<<endl;
return 0;
}
You say this: "This would not change the value stored at *p (it would still be 3)." -- I'm not sure why you say that. Yes, it would change the value stored at *p (which is the value of i). It changes it to 6.
The question is, why this wouldn't work:
int *p, i;
int main(){
*p=3;
here you attempt to dereference p and write something, but since p is uninitialized here (it can be 0, for example), you are trying to write to memory that you didn't allocate, thus this is a segmentation fault.
Also, if in the second example I wrote I added another assignment: [...] This would not change the value stored at *p (it would still be 3).
Actually, it would. Why would you think otherwise?
I'm interested in understanding why it works this way.
You're on the right track, just continue reading (e.g. this thread) and experimenting!

Method crashes every time I put the first integer into array. Bad operation?

I have a method which fills the array with integers:
void fill(int* a[], int dim1, int dim2)
{
int intinArray = 0;
for(int i=0;i<dim1;i++)
{
for(int j=0;j<dim2;j++)
{
cin >> intinArray;
a[i][j] = intinArray;
}
}
}
If I declare array in method main() like this:
int** tab;
fill(tab,3,3);
It crashes when I put the first integer in cin. Why? If there's a problem with this line:
a[i][j] = intinArray;
how should I change it?
The fundamental thing wrong with your code is that you declared pointers, but nowhere do you initialize the pointers to point somewhere. You treat the pointer as if it is a regular old 2 dimensional array of integer. So if it's as easy as that, why use pointers?
Given that this is a fundamental in pointer usage and you plainly aren't doing that, the solution is to review working code that uses pointer.
int main()
{
int *p; // uninitialized -- points to who-knows-where
*p = 10; // this is undefined behavior and may crash
}
Take that code and understand why it also may crash. That pointer points to "we don't know", and then you're assigning 10 to a location that is unknown to you, me, and everyone else reading this answer. See the problem? To fix it, you have to initialize the pointer to point somewhere valid, then you can dereference it and assign to it without error.
int main()
{
int *p; // uninitialized -- points to who-knows-where
int x = 20;
p = &x; // this is now ok, since p points to x
*p = 20; // now x changes to 20
}
Your problem is in this code
int** tab; // <- this one
fill(tab,3,3);
You declared a pointer, and are using it under the assumption that it is pointing to allocated memory. (I guess a source of confusion is that with C++ objects this isn't really the case)
A pointer is a pointer - it points to a location in memory. There's no guarantee that the value it points to is valid unless you explicitly make sure it is yourself.
Read PaulMcKenzie's answer for more about pointers.
Try
int tab[x][y] = {{0}};
fill(tab,3,3);
where x and y define your 2D array's width and height. You're going to have to handle bounds checking for your application.
Note that changing {{0}} to a non zero number will not initialize everything to that number.

Understand Reference and Dereferencing Operators?

Can someone please help me understand Reference and Dereference Operators?
Here is what I read/understand so far:
int myNum = 30;
int a = &myNum; // a equals the address where myNum is storing 30,
int *a = &myNum; // *a equals the value of myNum.
When I saw the code below I was confused:
void myFunc(int &c) // Don't understand this. shouldn't this be int *c?
{
c += 10;
cout<< c;
}
int main()
{
int myNum = 30;
myFunc(myNum);
cout<< myNum ;
}
int &c has the address to what's being passed in right? It's not the value of what's being passed in.
So when I do c+=10 it's going to add 10 to the memory address and not the value 30. Is that correct?
BUT... when I run this...of course with all the correct includes and stuff...it works. it prints 40.
Actually the ampersand in the function parameter list for myFunc is not an address operator, nor a bitwise and operator. It is a reference indicator. It means that within myFunc, the parameter c will be an alias of whatever argument is passed to it.
You have a few issues here.
your second line of code int a = &myNum; // a equals the address where myNum is storing 30 is wrong;
you can combine it with line 3 like so:
int *a = &myNum; // a equals the address where myNum is stored;
*a == myNum.
The type int & is read as "reference-to-int". Perhaps the Wikipedia article can help you understand what this means.
Both pieces of code are valid and your understanding of pointers in the first piece of code is correct. However, the ampersand (&) in the two pieces of code are actually different things. (Like how * is both the dereference and multiplication operator)
The second piece of code shows how the & can be used to pass variables to a function by reference. Normally if you had code like this:
int a;
void foo(int bar) {
bar = 3;
}
int main() {
a = 5;
foo(a);
// a still equals 5
}
The call to 'foo()' does not affect the variable you passed to it (bar or in this case, a). However if you changed this line:
void foo(int bar) {
to
void foo(int &bar) {
then it would affect the variable and at the end of the program above, the value of a would be 3.
In C++ when you pass things by reference using int &c you don't need to dereference. You only need to dereference pointers. If it was int *c then it would be necessary. Just remember in both cases you change the value of what was passed in the original caller so myNum is now 40.
Let's have a look at the assumptions first:
int myNum = 30;
// this won't compile. &myNum is the address of an int (an int *), not an int:
int a = &myNum;
// *a is a pointer to an int. It received the address of myNum (which is &myNum),
// and not its value
int *a = &myNum;
About the code:
void myFunc(int &c)
// c is passed by reference. This is a kind of "hidden pointer" that
// allows using the variable as if it was not a pointer but the pointed variable.
// But as this reference and the variable that was passed by the caller (myNum
// in your example) share the same address (this is the property of a reference),
// any modification of the value of c inside myFunc modifies it in the
// caller's scope too (so here, it modifies myNum).
{
c += 10;
cout<< c;
}
int main()
{
int myNum = 30;
myFunc(myNum); // displays 40
// What follows displays 40 as well, due to the fact
// c was passed by reference to myFunc that added 10 to it
cout<< myNum ;
}
So when I do c+=10 it's going to add 10 to the memory address and not
the value 30. Is that correct?
No, 10 was added to the value of c by myFunc.
As c is a reference (a "hidden pointer to") that received myNum, myNum was modified as well.

C++ Pointer Confusion

Please Explain the following code
#include <iostream>
using namespace std;
int main()
{
const int x = 10;
int * ptr;
ptr = (int *)( &x ); //make the pointer to constant int*
*ptr = 8; //change the value of the constant using the pointer.
//here is the real surprising part
cout<<"x: "<<x<<endl; //prints 10, means value is not changed
cout<<"*ptr: "<<*ptr<<endl; //prints 8, means value is changed
cout<<"ptr: "<<(int)ptr<<endl; //prints some address lets say 0xfadc02
cout<<"&x: "<<(int)&x<<endl; //prints the same address, i.e. 0xfadc02
//This means that x resides at the same location ptr points to yet
//two different values are printed, I cant understand this.
return 0;
}
*ptr = 8;
This line causes undefined behavior because you are modifying the value of a const qualified object. Once you have undefined behavior anything can happen and it is not possible to reason about the behaviour of the program.
Since x is a const int, the compiler will most likely, in the places where you use x, directly substitute the value that you've initialized with (where possible). So the line in your source code:
cout<<"x: "<<x<<endl;
will be replaced by this at compile time:
cout<<"x: "<<10<<endl;
That's why you still see 10 printed.
But as Charles explained, the behaviour is undefined, so anything could happen with code like this.