Why Third printf will print undefined value? - c

#include <stdio.h>
int main()
{
int i = 10;
int *p = &i;
foo(&p);
printf("%d ", *p);
printf("%d ", *p);
}
void foo(int **const p)
{
int j = 11;
*p = &j;
printf("%d ", **p);
}
What wii be the final output
Why Third printf will print undefined value ?

Within foo, you assign a value to *p which points to a location on the stack that's been allocated to foo. When foo returns, the stack is popped, and that location is free for reuse — but the p in main still points to it.
When you call printf in main the first time, it happens that that that location on the stack hasn't (yet) had any new data written to it, and so reading *p gives you 11, and you push that on the stack along with some other things for the call to printf, and it succeeds in printing 11. But the action of calling printf changes the data on the stack, including (potentially) the location that p (in main) points to, because the stack was popped after foo returned.
The second call then uses the data from that stack location again, which may have been changed by the first call to printf.
Moral of the story: Don't keep pointers to stack locations that have been popped.

the "i" in foo is stack-allocated, every thing will work fine until it goes off from the memory, so printf of foo will work fine,while the second printf and the third printf will work until the integer i of foo goes off from the memory. This is a system issue, it has the probability that the 2 last printf's work or don't work. If you wanna them work all the time you need to heap-allocate integer i of foo using mallo

Third printf is printing the right value. The problem is that j is an automatic local variable and it is no longer exist once function return. Therefore, p in main is not pointing to the place you are expecting and ultimately your program invokes undefined behaviour.
Possible solutions:
1. Use static keyword in the declaration of j
void foo(int **const p)
{
static int j = 11;
*p = &j;
printf("%d ", **p);
}
2. Dynamically allocate j
void foo(int **const p)
{
int *j = malloc(sizeof(int));
*j = 11;
*p = j;
printf("%d ", **p);
}

When void foo() is called ,new stack frame gets created on stack so int j = 11; being a local variable goes into this stack frame . So say int j is at address 0x000ffd with value 10 so your *p now stores this address . Now what happens when this function returns stack unwinds
During Stack Unwinding , it does all the work of cleanup. so all data which is into that stack frame gets destroyed so now that address 0x000ffd might have same value or something different but variable j is not associated to it now. So its undefined behavior

Related

Why is the pointer giving me this value?

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 does a pointer to pointer points on a printf output without making any changes with the pointer

I found this question, I should tell what will be the output.
#include <stdio.h>
int main()
{
int i = 10;
int *p = &i;
foo(&p);
printf("%d ", *p);
printf("%d ", *p);
}
void foo(int **const p)
{
int j = 11;
*p = &j;
printf("%d ", **p);
}
I think it shuold be 11 11 11. The answer is 11 11 unefined.
I checked with debugger and I found that the printf returns 3, and after the second print p point to that value 3. I don't know why it happens.
If someone can explain that would be great.
thanks.
That happens because you're assigning p to the address of a local variable, so the behavior is actually undefined both for the second and the third printf.
Once the function reaches the end, all its local variables fall out of scope. The memory they used is no longer reserved, so p points to an address which may still contain the value 11, but it may have been overwritten as well, as is the case on your computer (on mine I get 11 every time, but it's only a fortuity).
To make sure the value isn't lost, you could declare j as a static or global variable or allocate it with an *alloc function.

Passing double pointer to function [duplicate]

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

Behavior of call by reference

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.

can't understand the output of the simple c code about function call in linux

I write a simple code when I try to understand the function call. But I can't understand it's output.
#include <stdio.h>
int* foo(int n)
{
int *p = &n;
return p;
}
int f(int m)
{
int n = 1;
return 999;
}
int main(int argc, char *argv[])
{
int num = 1;
int *p = foo(num);
int q = f(999);
printf("[%d]\n[%d]\n", *p, q);
/* printf("[%d]\n", *q); */
}
Output:
[999]
[999]
Why *p is 999?
Then I modified my code like follows:
#include <stdio.h>
int* foo(int n)
{
int *p = &n;
return p;
}
int f()
{
int n = 1;
return 999;
}
int main(int argc, char *argv[])
{
int num = 1;
int *p = foo(num);
int q = f();
printf("[%d]\n[%d]\n", *p, q);
/* printf("[%d]\n", *q); */
}
Output:
[1]
[999]
Why *p is 1 here? I'm in Linux, using gcc but Clang got the same output.
Aside the fact that your code is provking undefined behaviour because you are returning a pointer to a stack variable, you were asking for why the behavior changes with changing the signature of f().
The reason why
The reason lies in the way the compiler builds the stackframe for the functions. Assume the compiler is building the stack frame as follows for foo():
Address Contents
0x199 local variable p
0x200 Saved register A that gets overwritten in this function
0x201 parameter n
0x202 return value
0x203 return address
And for f(int m) the stack looks quiet similar:
Address Contents
0x199 local variable n
0x200 Saved register A that gets overwritten in this function
0x201 parameter m
0x202 return value
0x203 return address
Now, what happens if you return a pointer to 'n' in foo? The resulting pointer will be 0x201. After returning foo the top of the stack is at 0x204. The memory remains unchanged and you can still read the value '1'. This works until calling another function (in your case 'f'). After calling f, the location 0x201 is overwritten with the value for parameter m.
If you access this location (and you do with your printf statement) it reads '999'. If you had copied the value of this location before invoking f() you would have found the value '1'.
Sticking to our example, the stackframe for f() would look like this as there are no parameters specified:
Address Contents
0x200 local variable n
0x201 Saved register A that gets overwritten in this function
0x202 return value
0x203 return address
As you are initializing the local variable with '1' you can read '1' at location 0x200 after invoking f(). If you now read the value from location 0x201 you'll get the contents of a saved register.
Some further statements
It is crucial to understand that the above explaination is to show you the methodology why you observe what you observe.
The real behavior depends on the toolchain you are using and the so called calling convetions.
One can easily imagine that it is sometimes hard to predict what will happen. It's a quiet similar situation to accessing memory after freeing it. That's why it's in general unpredictable what happens.
This behavior can even change with changing the optimization level. E.g. i can imagine that if you turn on -O3 for example, the observation will be different because the unused variable n will not appear anymore in the binary.
Having understood the mechanisms behind, it should be understandable why write accesses to the address retrieved from foo could lead to serious problems.
For the brave trying to prove this explaination through experiments
First of all it's important to see that above explaination does not rely on a real stack frame layout. I just introduced the layout in order to have a illustration easy to understand.
If you want to test the behavior on your own machine i suggest you take your favourite debugger and look at the addresses where the local variables and the parameters are placed to see what really happens. Keep in mind: Changing the signature of f changes the information placed on the stack. So the only real "portable" test is changing the parameter for f() and observe the output for the value p points to.
In the case of calling f(void) the information put on the stack differs massively and the value written at the position p is pointing to does not necessarily depend on the parameters or locals anymore. It can also depend on stack variables from the main-function.
On my machine for example the reproduction revealed that the '1' you read in the second variant comes from saving the register that was used to store '1' to "num" as it seems to be used for loading n.
I hope this gives you some insight. Leave a comment if you have further questions. (I know this is somewhat weird to understand)
You're invoking undefined behaviour. You can't return the address of a local variable (in this case, the argument int n) and expect it to be useful later.
A local variable, like n in your code here:
int* foo(int n)
{
int *p = &n;
return p;
}
"Disappears" as soon as the foo function finishes.
You can not use it, because accessing that variable might give you unpredictable results. You can write something like this, though:
int* foo(int* n)
{
*n = 999;
return p;
}
int main(int argc, char *argv[])
{
int num = 1;
int *p = foo(&num);
printf("[%d]\n", *p);
}
because your variable num still exists at the point of printing.
It's not easy without the assembler output, but this is my guess:
Locals and parameters are sotred on the stack. So when calling foo, it will return the address of the first parameter, which is on the stack.
In the first example, you pass a parameter to your second function, which will be also pushed on the stack, exactly where p points to. Therefore it overwrites the value of *p.
In the second example, the stack is not touched in the second call. The old value (of num) remains there.
In your first sample, when you do
int num = 1;
int *p = foo(num);
where foo() is
int* foo(int n)
{
int *p = &n;
return p;
}
When variabe num from main() is passed, it is passed by value to foo. In other words, a copy of the variable num, called n, is created on the stack. Both num and n have the same value, but they are different variables and therefore will have different addresses.
When you return p from foo(), the main() gets the value of an address that is different from the address of num delared in main()
The same explanation applies to your modified program.
Let's look at another example to clarify:
int i = 2;
int * foo()
{
return &i;
}
int main() {
i = 1;
int *p = foo();
return 0;
}
In this case, i is declared on the heap, and the same i is referred in both main() and foo(). Same address and same value.
Let's look at a third example:
int i = 2;
int * foo(int i)
{
return &i;
}
int main() {
int i = 1;
int *p = foo(i);
return 0;
}
Here, even though there is a global i, it is hidden by the local variable i in main(), and that is what gets passed to foo(). So, &i returned from foo, ie the value of p in main(), will be different from the address of the variable i declared in main().
Hope this clarifies about variable scope and passing by value,
This Undefined behaviour is due to the involvement of the stack
int *p = foo(num);
int q = f(999);
In the first case, when you say &num, it actually stores the address in the stack where num was stored. Then the foo(num) completes its execution and f(999) comes into action with parameter 999. Since the same stack is used, the same location in stack where num was stored now has parameter 999. And we know that the stack is contiguous.
This is the reason for both printing 999. Actually both tries to print the contents of the same location in the stack.
Whereas in the second case, num is not overwritten since no parameter is passed to f()
So, this prints as expected.

Resources