0

As far as I know , variable 'q' and is address gets out of scope after the function fun() ends. So , why the output of the code is "20 10" ?

int *p2;
void fun(int *ptr)
{
    int q=10;
    ptr=&q;
    p2 = ptr;
}

int main()
{
    int r=20;
    int *p = &r;
    fun(p);
    printf("%d %d",*p,*p2);
    return 0;
}
Santosh A
  • 5,173
  • 27
  • 37
  • 3
    Because it's undefined behaviour. – Jabberwocky Oct 31 '16 at 18:02
  • 1
    How do you tell garbage value from non-garbage value? Your `10` is a garbage value, as good as any other garbage value. – AnT stands with Russia Oct 31 '16 at 18:14
  • 1
    `10` is the garbage. – chux - Reinstate Monica Oct 31 '16 at 18:15
  • 3
    this is always a fun explanation: http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794#6445794 – yano Oct 31 '16 at 18:22
  • 1
    At some point, we may need a canonical UB Q&A to deduplicate with (like the "are floating point numbers broken?" one). The amount of C questions that arise because an OP depends on UB is ridiculously high, and very few of them are helpful to other users. –  Oct 31 '16 at 18:28

4 Answers4

3

As others have mentioned, saving the address of a local variable then attempting to dereference that address after the function returns is undefined behavior.

What that means is that your program could crash, it could exhibit strange behavior, or it could appear to work properly. This behavior does not need to be consistent from one compiler to the next for the same code or in the presence of a seeming unrelated change.

That being said, many compilers typically won't modify the portion of the stack used by a function after it returns. It's extra work that usually isn't needed. So immediately after fun returns, the local variables it has still contain their old values.

On the call to printf, the pointer p2 is dereferenced before printf is called. Since no other functions were called prior to this happening, the value of a from the last call to fun has not yet been overwritten. So you read the old value.

If you were to call some other function before calling printf, the memory location previously occupied by q will get overwritten, so that you'll likely see some other value.

To reiterate however, this is undefined behavior. Not all compilers are required to behave in this fashion. For example, in a high security environment a compiler might clear out stack memory after a function returns so that sensitive data used by that function cannot be recovered.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • On the flip side, on many embedded platforms, an interrupt that occurs after the function returns will likely clobber the stack frame formerly used by that function; since interrupts can often arrive at unpredictable times, that means that in most cases one can't say anything useful about the contents of former stack frames. – supercat Oct 31 '16 at 20:40
0

This is pure undefined behavior.

Accessing memory which is invalid invokes UB. (Just because you can write a code) You should not do it.

That 20 10 may very well be regarded as garbage because once you invoke UB, the output cannot be justified in any way.

FWIW, the issue is with accessing p2 by saying *p2, dereferencing p1 is just fine, as in C parameters are passed using pass-by-value, so any change to ptr inside the functions won't affect the actual variable ptr (not *ptr) in the caller.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

this is the worst kind of undefined behavior. The code seems to work correctly. And continues to do so during all test and QA. Then at midnight during busiest period with your most important customer it stops working.

BUt as other have said UB = UB, UB includes apparently working

pm100
  • 48,078
  • 23
  • 82
  • 145
0

As stated by others, you have undefined behavior so the output can be anything.

However, besides the undefined behavior you have a bug which is worth focusing on.

A rewrite of your code to avoid UB could be:

void fun(int *ptr){
    int q=10;
    ptr=&q;
 }

int main(){
    int r=20;
    int *p = &r;
    fun(p);
    printf("%d",*p);
    return 0;
}

This code is ok and the output will be 20. The point is that the pointer p is passed by value. So any changed made inside the function is lost when the function returns. In other words, p in main is not changed and still points to r.

If you want to change a pointer value in a function, pass it as a double pointer. Like void fun(int **ptr), assing it like *ptr = ... and call the function like fun(&p)

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63