I am trying to initialize the integer pointer "p" inside the "init_pointer" function. After the function returns I am printing the pointer and the dereferenced value twice. The first dereference prints the expected value 100, but the second dereference prints random values.
#include<stdio.h>
void init_pointer(int d, int **c){
(*c) = &d;
}
int main(){
int x = 100;
int *p;
init_pointer(x,&p);
printf("pointer = %p, value = %d\n",p,*p);
printf("pointer = %p, value = %d\n",p,*p);
return 0;
}
Output:
pointer = 0x7fffb4d4b9ac, value = 100
pointer = 0x7fffb4d4b9ac, value = 32567
The function has copied the value to a new local variable in init_pointer(int d, int **c)
d is local to init_pointer which was passed by main from x. Both x and d are separate variables whose addresses are different. Accessing the address of d outside init_pointer will lead to Undefined Behavior.
It would not make sense to call the function like this but this will work:
void init_pointer(int *d, int **c)
{
(*c) = d;
}
int main()
{
int x = 100;
int *p;
init_pointer(&x,&p);
printf("pointer = %p, value = %d\n",p,*p);
printf("pointer = %p, value = %d\n",p,*p);
return 0;
}
Output:
pointer = 0xbfde132c, value = 100
pointer = 0xbfde132c, value = 100
void init_pointer(int d, int **c){
(*c) = &d;
}
Here *c points to a local copy inside init_pointer(). Once init_pointer() returns, the address becomes invalid, and p in main() points to a freed address.
In init_pointer you assign the address of the parameter d to *c. The address of the parameter is a stack address.
In the first call to printf, the stack (although deallocated) is still intact, so p points to the discarded parameter d on the stack, which still has a value of 100, and *p is pushed first onto the stack.
In the second call to printf, the first call has overwritten the stack. Although the pointer still points to the same address, its value there has been overwritten by the push of p. Hence p (an address) is printed.
Notes: with "the stack (although deallocated)" I mean the stack of and below sp (intel; growing downward). Also, the stack can have been overwritten at any time, e.g. when interrupts occur.
Related
I was studying for a test with the following question with the given output :
#include <stdio.h>
int main()
{
int i = 10;
int *const p = &i;
foo(&p);
printf("%d\n", *p);
}
void foo(int **p)
{
int j = 11;
*p = &j;
printf("%d\n", **p);
}
Output : 11 11
I understand that the address of *p pointing to int i is passed to the function foo. Here, **p is a pointer pointing to *p, where *p points to int i.
In the function, **p pointer changes and points to int j, and the first printf is called and 11 is printed.
What I don't understand is the output from the 2nd printf function. Why is it printing 11, when it should be 10? I've checked and the value of int i and it did not change, so shouldn't dereferencing *p give 10 and not 11.
Can someone explain to me the logic behind what is happening and why is it happening?
First you asign p the address of i and you input the address of p to the function foo and inside the foo function the the value of p becomes what every the value in j (*p = &j). When the memory address changes in the foo function you are not changing it back.
NOTE: There the variable p is not passed by value, It is passed to the function by reference. So any change you do to the p variable inside the foo function will affect the p variable inside the main function because they have the same memory address
The line:
*p = &j;
makes the original variable
int *const p
point to the address of the local variable
int j
After foo is called, that local variable j has since been deallocated from the stack, but p is still pointing to that same stack location which still has that value of 11. So you are illegally accessing deallocated stack memory but it just happens to remain the value of 11. So it is printed a second time.
why the op is 20 ?? not 10 ? I think the op should be 10 but I don't know what happened? can you please explain it step by step
void fun(int *ptr)
{
int q=10;
ptr=&q;
}
int main()
{
int r=20;
int *p=&r;
fun(p);
printf("%d",*p);
return 0;
}
Values of function arguments are copies of what is passed from caller. Modifying in callee will not affect caller's local variables.
Non-static local variables will vanish on exiting its scope. Therefore, you must not dereference pointers to them after that.
To obtain 10, your code should be:
#include <stdio.h>
void fun(int **ptr) /* pass a pointer to modify caller's local variable */
{static int q=10; /* add static to prevent it from vanishing */
*ptr=&q; /* dereference the pointer */
}
int main()
{int r=20;
int *p=&r;
fun(&p); /* pass the pointer */
printf("%d",*p);
return 0;
}
This is p and r (addresses are for instance based)
---------------- ---------------- ----------------
| r 20 | | p 1234 | | q 10 |
---------------- ---------------- ----------------
^ ^ ^
|_ Address of r |_ Address of p |_ Address of q
= 1234 = 9876 = 12121
To fun(),
void fun(int *ptr) {
int q = 10;
ptr = &q;
}
you provide p as ptr (ie 1234), then set ptr to the address of q
fun: ptr = 12121
then fun ends, and ptr dies with it, the memory didn't change for r
To change something you have to pass the address of that thing. Even if it is a pointer.
Giving the address of p to fun
fun( &p );
and changing fun() to accept a pointer to pointer
void fun(int **ptr) { // <== pointer to pointer
int q = 10;
*ptr = &q; // <== change r indirectly
}
here, ptr has the address of the pointer p, ie 9876
*ptr = &q; // changes the value of `r`
It´s basically because of two reasons:
p in main() and ptr in fun() are two different pointers, and
You pass p by value, not by reference.
At the function call:
fun(p);
you just pass p by value; Means it passes the address of r (what is actually the value of p) to ptr.
With ptr = &q; in fun() you just assign the address of q to ptr, but not to p.
Therefore, the output of dereferencing p at:
printf("%d",*p);
is of course 20, as p still point to r -> the value of p didn´t changed.
If you instead pass p by reference and declare ptr as pointer to pointer (**), plus qualify q with static qualifier (because function-local automatic variables will be destroyed after the function is executed once):
void fun(int **ptr) // ptr is declared as pointer to pointer to int.
{
static int q = 10; // q is static -> It won´t get destroyed after returning from `fun()`.
*ptr = &q; // dereferencing ptr to assign the address of q to p.
}
int main()
{
int r = 20;
int *p = &r;
fun(&p); // Notice the `&` to gain the address of `p`, not `r`.
printf("%d",*p);
return 0;
}
The output would be 10 as we actually assigned the address of q to p.
As a side note: It is considered as bad programming style to refer to static-qualified function-local variables from a caller. I just showed this to you for the educational purpose and to show the difference to your provided code.
Try to assign an object pointed to in the caller, here f.e. r, by a passed pointer inside of the called function, here ptr, with the actual value of the object in the called function, here q.
This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 5 years ago.
I was trying out some pointer and function interaction and found out this behavior. The first printf prints 100 but the second printf prints 0!
Can somebody help me understand why?
void ptr_change (int **p)
{
int y = 100;
*p = &y;
}
int main ()
{
int x = 7;
int *p = &x;
ptr_change(&p);
printf("\nPtr = %d", *p);
printf("\nPtr = %d", *p);
return 0;
}
Compile:
gcc ptr2.c
Run and give output:
./a.out
Ptr = 100
Ptr = 0
y is an automatic local variable which will no longer exist after the function returns and you are assigning the address of an automatic local variable to the pointer.
In the main function you are dereferencing a pointer which no longer points to a valid location. This invokes undefined behavior. You can't expect anything good once there is undefined behavior of your code.
You return the address of an automatic variable from a procedure. The variable is no longer valid after the function returns. What happens next is called Undefined Behavior, however, an explanation for Intel machines and e.g. VC2008 is:
ptr_change(&p);
This places in p the address of the local variable y. After return from function ptr_change the stack space used by the function is released.
printf("\nPtr = %d", *p);
This first printf re-uses the stack space used earlier by ptr_change. It pushes 2 parameters onto the stack. The first parameter overwrites the stack space used by &p in your function call. y is not yet overwritten. The *p parameter of printf gets this value and pushes it onto the stack. The call to printf now overwrites int y.
printf("\nPtr = %d", *p);
As int y has been overwritten in the previous cal to printf, this call to printf prints garbage.
Note that any other form of undefined behavior is possible!
The value of y in
void ptr_change (int **p)
{
int y = 100;
*p = &y;
}
exists only temporary on stack as an automatic variable.
Once the function returns that location is not longer valid.
Compare the following program which passes pointer to the variable a and initializes pointer p.
#include<stdio.h>
void ptr_change2 (int **p, int *a)
{
*p = a;
}
int main ()
{
int x = 7;
int z = 8;
int *p = &x;
printf("\nPtr = %d", *p);
ptr_change2(&p,&z);
printf("\nPtr = %d", *p);
return 0;
}
Output:
Ptr = 7
Ptr = 8
*p = &y
is incorrect, you're assigning the address of y to the value of p.
try this instead:
p = &y
they will now have the same base address.
y = 100;
then print the pointer value of p
printf("%d", *p);
#include<stdio.h>
int q = 10;
void fun(int *p){
*p = 15;
p = &q;
printf("%d ",*p);
}
int main(){
int r = 20;
int *p = &r;
fun(p);
printf("%d", *p);
return 0;
}
I was playing with pointers. Could not understand the output of this.
Output is coming as 10 15.
Once p is pointing to address of q, why on returning to main function it's value changes? Also why it changed to the value '15' which was assigned to it in the function before '10'.
Because p is fun() is not the same p in main(). p , in each function, is local. So changing one doesn't affect other.
In C, all function parameters are passed by value, including pointers.
*p = 15; will set r to 15 as *p is pointing to the memory occupied by r in main() prior to its reassignment to &q;
Your reassignment p = &q; does not change what p points to in the caller main(). To do that, you'd need to doubly indirect the pointer, i.e. change the function prototype to void fun(int **p){, call it using fun(&p);, and reassign using *p = &q;.
Two steps:
First call to fun(), assigning the address of global int q [holding value 10] to p inside the fucntion scope and printing it. The first output ==> 10;
Once the call returns from fun(), it will hold the previous address, [passed from main()] and hence, will print the value held by that address [which is 15, modified inside fun()].
In my program, I am a passing a pointer to a function. In that function, I am making the passed pointer to point to a location what another pointer points. When returned from function it no longer points to its new location, instead it points to its original location. As I am passing by call by reference, it should point to its new location. Why is this happening?
// a program to show behavior of call by reference
#include <stdio.h>
#include <stdlib.h>
void ptrAllocation(int *p)
{
int k = 10 ;
int *t = &k;
p = t ;
printf("\np now points : %d",*p);
}
int main()
{
int i = 5 ;
int *a = &i;
ptrAllocation(a);
printf("\na now points : %d",*a);
}
Output:
p now points : 10
a now points : 5
I know the problem can be solved if I make a function like:
void ptrAllocation(int **p)
{
int k = 10 ;
int *t = &k;
*p = t ;
printf("\np now points : %d",**p);
}
But I am not getting the clear picture of what is happening exactly in the program from the point of view of pointers, location, stack?
MY PROBLEM:
Is that the pointer k points to whatever pointer t points in the function ptrAllocation, but as the function returns, there no longer exists pointer t, hence pointer p points to its original location.
Is it not the case that when assigning a pointer to a pointer like in p = t, both pointers p and k point to the same location and not that p points to t and t points to the location.
Please describe how the stack and the pointers work in the program above.
You are passing by value, not by reference. What you pass by value is a pointer, but the pointer is still passed by value. You can change what it points at; you can't change the pointer in the calling function. If you wanted to do that, you'd have to pass a pointer to the pointer, as in your second code fragment.
Here's a derivative program based on your code, and its output from a 64-bit build on Mac OS X 10.8.3. I used 12 in the address printing to give uniform width pointer output on this machine; you can tune it to suit your machine.
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
static int q = 42;
static void ptrAllocation(int *p, int **z)
{
printf("p now points at: %2d (0x%.12" PRIXPTR ")\n", *p, (uintptr_t)p);
printf("z now points at: %2d (0x%.12" PRIXPTR ") (0x%.12" PRIXPTR ")\n", **z, (uintptr_t)*z, (uintptr_t)z);
int k = 10;
int *t = &k;
*z = &q;
p = t;
printf("After:\n");
printf("p now points at: %2d (0x%.12" PRIXPTR ")\n", *p, (uintptr_t)p);
printf("z now points at: %2d (0x%.12" PRIXPTR ") (0x%.12" PRIXPTR ")\n", **z, (uintptr_t)*z, (uintptr_t)z);
}
int main(void)
{
int i = 5;
int j = 7;
int *a = &i;
int *b = &j;
printf("Before:\n");
printf("a now points at: %2d (0x%.12" PRIXPTR ")\n", *a, (uintptr_t)a);
printf("b now points at: %2d (0x%.12" PRIXPTR ")\n", *b, (uintptr_t)b);
ptrAllocation(a, &b);
printf("a now points at: %2d (0x%.12" PRIXPTR ")\n", *a, (uintptr_t)a);
printf("b now points at: %2d (0x%.12" PRIXPTR ")\n", *b, (uintptr_t)b);
}
Sample output:
Before:
a now points at: 5 (0x7FFF59E1852C)
b now points at: 7 (0x7FFF59E18530)
p now points at: 5 (0x7FFF59E1852C)
z now points at: 7 (0x7FFF59E18530) (0x7FFF59E18538)
After:
p now points at: 10 (0x7FFF59E18534)
z now points at: 42 (0x000105DE8050) (0x7FFF59E18538)
a now points at: 5 (0x7FFF59E1852C)
b now points at: 42 (0x000105DE8050)
Studying the output should help you understand better what is going on. You can print more address values if you need to.
Please describe how the stack and pointers work in the program above.
I'll discuss the program I showed because the addresses are available for discussion.
The variable q is located at address 0x000105DEE8050. Inside main(), variable i is stored on the stack at memory location 0x7FFF59E1852C; the variable j is stored at memory location 0x7FFF59E18530. The variable a contains the address of i; b contains the address of j; the address of b itself is 0x7FFF59E18538; the address of a is not shown in the output.
When ptrAllocation() is called, the value of a is pushed onto the stack, and the address of b is also pushed onto the stack. It is an implementation detail which order the values are pushed.
Inside ptrAllocation(), the variable p contains a copy of the value in a in the main() function. The variable z contains the address of b in the main() function. The variable k is on the stack; the variable t contains the address of k.
The assignment *z = &q; assigns the address of q to the pointer b via the argument z; it changes what b points at by changing the value of b in the calling function — which is only possible because the address of b was passed.
The assignment p = t; changes the local variable p (which contains a copy of what is in the variable a in main()) so that it points to what t points at, which is k. Therefore, the 'After' print statements note that p points at the value 10. The value that **z points at is in q and is still 42; *z is the address of q.
On return, a in the main() code is unchanged because its address was not passed to ptrAllocation(), but b is changed because its address was passed to ptrAllocation() and ptrAllocation() modified the pointer.
As noted in the comments to the question, your second implementation of ptrAllocation() is flawed too:
void ptrAllocation(int **p)
{
int k = 10 ;
int *t = &k;
*p = t ;
printf("\np now points : %d",**p);
}
After calling this function, the pointer passed to it cannot reliably be dereferenced because *p points to a local variable which ceases to be valid once ptrAllocation() returns. You could fix this issue by making k into static int k = 10;, or by arranging for *p to point to some other int value that has a scope outside the function — a variable defined outside the function, or a dynamically allocated variable:
void ptrAllocation(int **p)
{
static int k = 10;
int *t = &k;
*p = t ;
printf("p now points : %d\n", **p);
}
Or:
void ptrAllocation(int **p)
{
*p = malloc(sizeof(*t));
if (*p != 0)
{
**p = 10;
printf("p now points : %d\n", **p);
}
}
Note, incidentally, how the code I've left has the newlines at the end of each printf() statement. Get into the habit of placing newlines at the end of lines of output. If you don't, you don't know when the output will appear (because it may be held up until the next time a newline is generated).
You are changing the pointer in function and not in the main code. Therefore only the copy will be changed. In the later case you change the location of pointer so the value at that address is changed. Take it like variables, when you change the copy, nothing happens to the original but when you change the location, the variable is changed. So you have to pass the address of pointer to change it.
The C language only implements call by value. Call by reference refers to passing (by value) a pointer p, and then using *p to manipulate what it points at (references).
If you want a function to change a pointer, you have to reference the pointer, such as by forming a pointer to pointer, and pass the reference to the function using call by value. The terms "reference" and "pointer" may be used nearly interchangeably in C — referencing is just what a pointer does.
In C++ call by reference is a language feature, but in C it's an idiom.