This is a code snippet I created for learning purposes in C++, I am currently trying to teach myself. My question is:
Why does *ptr = 30 change the output values of the two last cout statements in my main? (the output is 30, 30, 30). Consequently, why does int y = 30; and ptr = &y; not change the output in my main, and stay local to the function? (if I comment out *ptr = 30, and not the former two statements, the output is 30, 5, 5)
If I change the function input to void printPointer(int *&fptr) -- and comment out only *ptr = 30 -- then *ptr in my main will be modified, but not x. I understand this, as the pass by reference is modifying the pointer, but not how my first statement modifies *ptr and x in my main.
#include <iostream>
using namespace std;
void printPointer(int *fptr);
int main()
{
int x = 5;
int *ptr = &x;
printPointer(ptr);
cout << *ptr << endl;
cout << x << endl;
return 0;
}
void printPointer(int *fptr)
{
// int y = 30; // this does not change the output of the last two couts in main, output = 30, 5, 5
// fptr = &y;
*fptr = 30; // uncommenting this and commenting out the former two statements: output = 30, 30, 30
cout << *fptr << endl;
}
*ptr = 30 changes the value of what is being pointed at. In your case, you have set ptr to point at x (when you did ptr = &x and then passed that in as the argument to printPointer()). So the value of x is changed.
When you instead do int y = 30; fptr = &y;, all you're doing is changing fptr to point at a different variable. That's it. You're not changing the value of what is being pointed to (i.e. the value of x). And you're not affecting ptr, because fptr is a separate, local, variable. So ptr still points at x, and x is still 5.
When you modify your function to take the pointer by reference, then changing fptr to point at y also changes ptr, because they are the same variable.
*fptr = 30 would dereference the address stored in fptr and write 30 at the position in memory. this address in memory you gave to the function with printPointer(ptr). ptr in this case was the address of x, which you assigned to ptr with ptr = &x.
int y= y declares a variable local to the function.
fptr = &y assigns the address of y to fptr (and overwrites the value from ptr). so the last line in this case would change the local variable y instead of x.
If I understand correctly, you're asking about two pieces of code. The first one is what you posted:
#include <iostream>
using std::cout;
void f(int* fptr) {
*fptr = 30; // 11
cout << "*fptr = " << *fptr << '\n'; // 12
}
int main() {
int x = 5; // 1
int* ptr = &x; // 2
f(ptr); // 21
cout << "*ptr = " << *ptr << '\n'; // 22
cout << "x = " << x << '\n'; // 23
}
In this case, the pointer always points to x, and in the function, you still change the value of x, as that is what fptr is pointing to. If it helps, here's a demonstration of the value of the variables at the end of every line: NE means a variable does not currently exist.
1. x = 5, ptr = NE, fptr = NE
2. x = 5, ptr = &x, fptr = NE
11. x = 30, ptr = &x, fptr = &x
12. x = 30, ptr = &x, fptr = &x
21. x = 30, ptr = &x, fptr = NE
After that, the values do not change, and all three statements will print 30.
The second one is:
#include <iostream>
using std::cout;
void f(int*& fptr) {
int y = 30; // 11
fptr = &y; // 12
cout << "*fptr = " << *fptr << '\n'; // 13
}
int main() {
int x = 5; // 1
int* ptr = &x; // 2
f(ptr); // 21
cout << "*ptr = " << *ptr << '\n'; // 22
cout << "x = " << x << '\n'; // 23
}
In the first case, the pointer is passed by reference, and it points to y. In fact, in this case, line 21 involves undefined behaviour, as y no longer exists. Again, line-by-line analysis:
1. x = 5, y = NE, ptr = NE, fptr == NE
2. x = 5, y = NE, ptr = &x, fptr == NE
11. x = 5, y = 30, ptr = &x, fptr == ptr
12. x = 5, y = 30, ptr = &y, fptr == ptr
13. x = 5, y = 30, ptr = &y, fptr == ptr
21. x = 5, y = NE, ptr = &y, fptr == NE
The values again do not change after this: however, on line 22, you try to take the address of ptr. As you can see, *ptr = y = NE, and thus the behaviour is undefined. The output can be anything.
(Another note is that you should avoid using namespace std; as it can cause name clashes; use using std::cout; and similar, as in the code above.)
Related
I have made a fun called show()
in it i have declared a static and a non -static variable ;
I am observing one thing that each time my non-static local variables are getting same memory address when i am calling it .
i just want to know that this happens always or it is just a coincident;
#include<iostream>
#include<cstring>
using namespace std;
void show()
{
static int x = 10;
int y = 20;
cout<<"Address of y = "<< &y<< endl;
cout<< "x = "<< x<< " , y = "<< y<< endl;
x++;
y++;
}
int main()
{
show();
int x = 10;
cout<< x<< endl;
cout<< "len = "<< strlen("Kumar")<< endl;
show();
show();
return 0;
}
Out put of the program
Address of y = 0xd01f5ffc6c
x = 10 , y = 20
10
len = 5
Address of y = 0xd01f5ffc6c
x = 10 , y = 20
Address of y = 0xd01f5ffc6c
x = 10 , y = 20
It's related entirely to your call stack.
I added this method to your code:
void foo() {
cout << "\nCalled from Foo.\n";
show();
}
I then called foo() from main(). My output:
-$ g++ Foo.cpp -o Foo && Foo
Address of y = 0x7ffc709566d4
x = 10 , y = 20
10
len = 5
Address of y = 0x7ffc709566d4
x = 11 , y = 20
Address of y = 0x7ffc709566d4
x = 12 , y = 20
Called from Foo.
Address of y = 0x7ffc709566c4
x = 13 , y = 20
As you can see, it moved.
You should take the time to learn about stacks and the stack pointer, and how C and C++ store local variables.
Assume the following function in C++:
#include <iostream>
int& change(int& a){
a = 6;
return a;
}
int main(){
int a = 5;
int b = change(a);
std::cout << b << std::endl;
return 0;
}
Running this will return:
6
My question is, if I change the return type from int& to int, compiler won't complain and it will still print 6. So how does retuning a reference work in C++? (comparing it with returning a pointer in C)
Reference, like a pointer is implemented by storing the address of an object.
Returning by Value means that it is returning a copy of the old object.
Returning by Reference means that it is returning the address of the old object.
#include <iostream>
int& change_ref(int& a) {
a = 6;
return a;
}
int change_value(int& a) {
a = 6;
return a;
}
int main() {
int a = 5;
change_ref(a) = 7;
// change_value(a) = 7; compile error
std::cout << a << std::endl;
int& a1 = change_ref(a); // return reference of a
// now a1 ref the a
a1 = 10;
// print a = 10 and a1 = 10
std::cout << a << " " << a1 << std::endl;
int a2 = change_value(a); // return a value of a, so return is 6
// value of a is 6 and define a new value a2
a2 = 11;
// set a2 to 11 and not change a
// print a = 6, a1=6, a2= 11
std::cout << a << " " << a1 << " " << a2 << std::endl;
return 0;
}
You can return by reference as long as it isn't a locally declared variable (as those would be removed from the stack). Returning by reference just means that it is not returning a copy of the object but the actual object.
You are calling the function change() by reference and then updating the actual value of a to 6. Since the value of a updated to 6, so irrespective of return type a will carrying the updated value and always print 6 in the given example.
NOTE: Declared data of b is int, hence you are not printing any reference.
I am trying to grasp come concepts related to pointers and references. In the code snippet below, I call function shifting() several times from a for loop while iterating a linked list. With each iteration, int *ptr and int count are changed and passed to the function shifting(). Also, some other pointers and integer variables are passed by reference.
Doubts:
can I assign pointer references like shown in shifting() function? Same question for integer val references.
What is going on in the background? I read that references cannot be re-assigned. Is this not the case here every time shifting() is called?
please note, *ptr and count are NOT passed by reference. They are only to be read.
void shifting(int const * ptr, int const * &ptr6, int const * &ptr7, int const * &ptr8,
int count, int &val6, int &val7, int &val8)
{
ptr8 = ptr7; val8 = val7;
ptr7 = ptr6; val7 = val6;
ptr6 = ptr; val6 = count;
}
int main()
{
int const *ptr6 = NULL; int val6 = 0;
int const *ptr7 = NULL; int val7 = 0;
int const *ptr8 = NULL; int val8 = 0;
int count = 0;
// myList: a linked-list
// front(): gives first element of list
// back(): gives last element of list
// nextElement(): gives next element of list
for (int *ptr = myList.front(); ptr != myList.back(); ptr = nextElement();)
{
count++;
shifting(ptr, ptr6, ptr7, ptr8, count, val6, val7, val8);
}
}
EDIT: I tried the above example (after posting here) with only integer part as shown below:
#include <iostream>
using namespace std;
void shifting( int i, int &val6, int &val7, int &val8 )
{
val8 = val7;
val7 = val6;
val6 = i;
}
int main()
{
int val6 = 0;
int val7 = 0;
int val8 = 0;
for (int i = 1; i <= 10; i++)
{
shifting(i, val6, val7, val8);
cout <<"i: "<<i<<" val6: "<<val6<<" val7: "<<val7<<" val8: "<<val8<<endl;
}
return 0;
}
I got this output as below. How come references are being re-assigned??? I read they are not supposed to reassign.
i: 1 val6: 1 val7: 0 val8: 0
i: 2 val6: 2 val7: 1 val8: 0
i: 3 val6: 3 val7: 2 val8: 1
i: 4 val6: 4 val7: 3 val8: 2
i: 5 val6: 5 val7: 4 val8: 3
i: 6 val6: 6 val7: 5 val8: 4
i: 7 val6: 7 val7: 6 val8: 5
i: 8 val6: 8 val7: 7 val8: 6
i: 9 val6: 9 val7: 8 val8: 7
i: 10 val6: 10 val7: 9 val8: 8
can I assign pointer references like shown in shifting() function? Same question for integer val references.
Yes. But when you do so, you are assigning to the referent, not the reference.
What is going on in the background?
This is what's (effectively) going on in the background. That is to say, if you wanted to achieve the same effect without references, you might do this:
void shifting(int const * ptr, int const ** ptr6, int const ** ptr7, int const ** ptr8,
int count, int* val6, int *val7, int *val8)
{
*ptr8 = *ptr7; *val8 = *val7;
*ptr7 = *ptr6; *val7 = *val6;
*ptr6 = ptr; *val6 = count;
}
And at the place where you call it:
shifting(ptr, &ptr6, &ptr7, &ptr8, count, &val6, &val7, &val8);
I read that references cannot be re-assigned.
That is correct. Although I prefer the term re-bound. You can do what looks like an assignment to a reference. But that is actually an assignment to the referent. In fact, after a reference is created, thereafter, its name acts as an alias to the referent. Any operation on the reference (with the exception of decltype) is as if done on the referent.
Is this not the case here every time shifting() is called?
No. When you use the assignment operator on a reference, you are actually assigning to the referent, not the reference.
Your example is extremely convoluted, perhaps something simpler will clear things up.
int a = 0;
int b = 77;
int& ra = a; // ra is a reference to a, and always will be
int& rb = b; // rb is a reference to b, and always will be
ra = b; // ra is still a reference to a, but now a == 77
ra = 999; // now a == 999
rb = ra; // rb is still a reference to b, but now b == 999
To further clarify, the above example is exactly equivalent to this:
int a = 0;
int b = 77;
a = b;
a = 999;
b = a;
Or this example using pointers:
int a = 0;
int b = 77;
int* pa = &a; // pa is a pointer to a, this can change, but won't in this example
int* pb = &b; // pb is a pointer to b, this can change, but won't in this example
*pa = b; // pa is still a pointer to a, but now a == 77
*pa = 999; // now a == 999
*pb = *pa; // pb is still a pointer to b, but now b == 999
I think you may partly be confusing yourself by re-using variable names between the function and the caller: For example, within shifting val6 is a local variable, bound to whatever it was called with, which just happens to be an external variable with the same name.
#include <iostream>
void test(int& i) {
std::cout << "test/i = " << i << '\n';
}
int main() {
int i = 1;
int j = 42;
test(i);
test(j);
}
This outputs (see http://ideone.com/lRNINP)
test/i = 1
test/i = 42
The significance of being a local reference is that it goes away at the end of the function iteration and is reformed with the new arguments at the next iteration.
I got this output as below. How come references are being re-assigned???
They aren't, the values are simply shifting as your function appears to aim to do: (see http://ideone.com/oCmOPk)
#include <iostream>
int main() {
int i = 0;
int& ir = i; // not an assignment, a binding
ir = 1; // pass '1' thru 'ir' to 'i'.
std::cout << "ir " << ir << ", i " << i << "\n";
int j = 0;
int& jr = j;
jr = 42; // pass '42' thru 'jr' to 'j'
std::cout << "jr " << jr << ", j " << j << "\n";
ir = jr; // pass the *value* of 'jr' thru 'ir' to 'i'
j = 99;
// if ir is rebound to jr, both of these will be 99.
std::cout << "ir " << ir << ", i " << i << "\n";
std::cout << "jr " << jr << ", j " << j << "\n";
}
Output:
ir 1, i 1
jr 42, j 42
ir 42, i 42
jr 99, j 99
In following case I get NumRecPrinted = 0 , that is num is 0
int main()
{
int demo(int *NumRecPrinted);
int num = 0;
demo(&num);
cout << "NumRecPrinted=" << num; <<<< Prints 0
return 0;
}
int demo (int *NumRecPrinted)
{
int no_of_records = 11;
NumRecPrinted = &no_of_records;
}
You are assigning the address to the pointer, and not the value to the pointed-to. Try it like this instead
int demo (int *NumRecPrinted)
{
int no_of_records = 11;
*NumRecPrinted = no_of_records;
}
No!
*NumRecPrinted = no_of_records;
See "*" means "value of" and "&" means "address of". You want to change the "value of" NumRecPrinted, which is why the above works. What you did was to give NumRecPrinted the "address of" num_of_records.
All you did was pointer the local pointer-to-int NumRecPrinted at a new integer inside the demo function.
You want to change the integer it points to, not change where it points.
*NumRecPrinted = no_of_records;
You can see in your version that you're taking the address of a local variable, and you know it isn't the address of that variable you care about, but its value.
As others have pointed out, the * = the value of and & = address of. So you were just assigning a new address to the pointer inside the method. You should:
*NumRecPrinted = no_of_records;
See this excellent tutorial on Pointers. E.g.:
int firstvalue = 5, secondvalue = 15;
int * p1, * p2;
p1 = &firstvalue; // p1 = address of firstvalue
p2 = &secondvalue; // p2 = address of secondvalue
*p1 = 10; // value pointed by p1 = 10
*p2 = *p1; // value pointed by p2 = value pointed by p1
p1 = p2; // p1 = p2 (value of pointer is copied)
*p1 = 20; // value pointed by p1 = 20
You want
*NumRecPrinted = no_of_records;
That means, "set the thing NumRecPrinted points to to equal no_of_records".
Can you explain me which is the mechanism behind the next code samples (I think I know but I need second opinion):
1)--------------------------
using namespace std;
int * f(int x) {
return &x;
}
int * g(int x, int y) {
return &y;
}
int * h(int x, int y, int z) {
return &z;
}
int main() {
cout << *f(42) << endl;
int * y1 = g(43, 44);
int * y2 = g(45, 46);
cout << *y1 << ", " << *y2 << endl;
int * z1 = h(47, 48, 49);
int * z2 = h(50, 51, 52);
cout << *z1 << ", " << *z2 << endl;
return 0;
}
2)--------------------------
int *a, *b;
void f(int x) {
int i[3];
i[0] = x;
i[1] = x + 1;
i[2] = x + 2;
a = i;
}
void g(int x) {
int i[3];
i[0] = x;
i[1] = x + 1;
i[2] = x + 2;
b = i;
}
int main() {
f(1);
printf("a = {%d,%d,%d}\n", a[0], a[1], a[2]);
g(2);
printf("a = {%d,%d,%d}\n", a[0], a[1], a[2]);
}
3)--------------------------
int main() {
char * hello = "hello, world!" + 3;
char * charstring = 'h' + "ello, world!";
printf("hello=%s, charstring=%s.\n", hello, charstring);
return 0;
}
Thank you.
I would expect those programs to crash or do other weird things when you run them.
Example 1: The functions f, g and h are returning the memory addresses of their arguments. Note that those arguments are stored on the stack, and when the functions return, the stack is unwound and the addresses will not be valid anymore. You could get lucky and the value will still be there, but you could just as well have the program crash or return some random value that's not the value that you passed to the function.
Example 2: The functions f and g set the global variables a and b to the addresses of local variables declared in the functions. Just like in the first example, those local variables will be gone when the functions return, leaving a and b pointing to something invalid.
Example 3: This is doing weird pointer arithmetic. hello will probably point to the address of the text plus 3, so you'd probably get "lo, world!" printed for this (but it could also be different, depending on how pointer arithmetic works on your particular platform). The case with charstring is similar, only here you add 'h' (ASCII value 104 - so you're adding 104 to the pointer). This will most likely crash the program.
I think it's a little easier for a beginner to understand these concepts if you explain step by step what is happening in the background.
1.
cout << *f(42) << endl; // Call f with the value 42
int * f(int x) { // Push an integer, x, on the stack (x = 42)
return &x; // Return a pointer to var x
} // Pop x off the stack
// Pointer now points to a memory address that is unallocated,
// which will crash the program when it tries to use that memory,
// which it does with cout
2.
f(1); // Call f with the value 1
void f(int x) { // Push an integer, x, on the stack (x = 1)
int i[3]; // Declare an int* with space for 3 vals (local! stack!)
i[0] = x; // Define values of the array
a = i; // Set a equal to i, beginning of array
} // i is now out of scope, and since it was declared as locally,
// rather than with malloc (or new in c++), it is on the stack
// and has now been popped off, so a points to a memory address
// that the OS *should* have marked as inaccessible
3.
char * hello = "hello, world!" + 3; // hello is a char*, a pointer that
// points to the beginning of an array
// of characters. Adding 3 will increment
// the pointer three characters after the
// first character.
char * charstring = 'h' + "ello, world!"; // charstring is a char*, a pointer that
// points to the beginning of an array
// of characters. This time, it would point
// to "ello, world!". However, the addition
// of 'h' will shift the character position
// by 104 characters because that is the
// value of ascii 'h'.