0

So a friend of mine showed me a weird thing with printf() in C.

#include <stdio.h>
#include <string.h>
int *init()
{

    int a =10;
    int *p = &a;
    return p;
}
int main()
{

    int *a = init();
    printf("FIRST printf and value of a: %u\n", *a);
    printf("SECOND printf and value of a %u\n", *a);
    return 0;
}

Now I expected to get the same result at both printf() calls but that's not the case as seen in this snip:output Of course, you can try it on your own system to convince yourselves. I think it has something to do with the printf() function frame but I don't understand fully enough what is happening. Can you explain it to me please?

  • 2
    The local variable in the function has gone out of scope but retains its value to be a parameter to the first invocation of `printf()`. Because that region of memory is available, the first call to `printf()` reuses that region, changing the value at that location. The second call to `printf()` again uses a value it shouldn't because it is out of scope. Lesson: Don't write sloppy code like this. – Fe2O3 May 03 '23 at 05:45
  • 1
    `a` is a local variable. Using the address of `a` in the calling function results in [undefined behavior](https://stackoverflow.com/questions/2397984). – user3386109 May 03 '23 at 05:45
  • Prefer giving as us data as text instead of screen shots. The latter is not searchable. – Allan Wind May 03 '23 at 06:03
  • `init` returns a [dangling pointer](https://en.wikipedia.org/wiki/Dangling_pointer), and it is [UB](https://en.wikipedia.org/wiki/Undefined_behavior) to dereference it. – wohlstad May 03 '23 at 06:41
  • So the question to ask is, what *would* you expect it to print? 10? Why? Where does the pointer `a` point, and what value is stored there? And does that value still actually exist? – Steve Summit May 03 '23 at 16:50
  • 1
    See also [this epic Eric Lippert analogy](https://stackoverflow.com/questions/6441218#6445794). – Steve Summit May 03 '23 at 16:51

1 Answers1

4

Returning the address of a local variable is undefined behavior as its lifetime expired when the function returned. On my platform the local variable is stored on the stack, and the memory where the variable a or p was stored was overwritten by subsequent function calls (printf()).

Consider these alternatives instead:

  1. Pass in pointer to the caller's variable.
int *init1(int *a) {
    *a = 10;
    return a;
}

int main() {
   int a;
   init1(&a);

   int *b = init1(&(int) {0}); 
}
  1. Return value instead of a pointer.
int init2() {
   return 10;
}

int main() {
   int a = init2();
}
  1. Dynamically allocate space for your variable, and caller takes on the obligation to free the variable when done. Usually you name such a function "create" or "new" rather than "init".
#include <stdlib.h>

int *init3() {
    int *p = malloc(sizeof *p);
    if(p) 
        *p = 10;
    return p;
}

int main() {
   int *a = init3();
   free(a);
}
Allan Wind
  • 23,068
  • 5
  • 28
  • 38
  • Variable `a` is local, so it's allocated on the stack. When function `init1` ends, stack frame is destroyed and we're back to `main`, address containing `a` hasn't been re-writen so we still have the value. It's pushed to the stack from `main` before `printf` call, but after first `printf` call, the addres where `a` was stored in the stack is likely to contain something else, re-writen in first `printf` call. As mentioned earlier, this is UB. – AR7CORE May 03 '23 at 11:06
  • @AR7CORE Even the first printf() is undefined behavior. We just happen to like that behavior more. UB is a language specification domain while stacks an implementation detail and I tried to separate the two in my answer. – Allan Wind May 03 '23 at 16:39