The below code is given. You need to determine what the output will be, or if there is an error.

#include<stdio.h>

int main()
{
    int *j;
    int *fun();
    j = fun();
    printf("%d\n",*j);
    printf("%d",*j);
    return 0;
}

int *fun()
{
    int k = 35;
    return(&k);
}

What is given in a well known book

This was the explanation given in a well known book Let Us C by Yashavant Kanetkar (5th Edition)

Here we are returning an address of k from fun() and collecting it in j. Thus j becomes pointer to k. Then using this pointer we are printing the value of k. This correctly prints out 35. Now try calling any function (even printf()) immediately after the call to fun (). This time printf () prints a garbage value. Why does this happen? In this case, when the control returned from fun () though k went dead it was still left on the stack. We then accessed this value using its address that was collected in j. But when we precede the call to printf () by a call to any other function, the stack is now changed, hence we get the garbage value.

please ignore this answer, as it is not correct.

Actual answer

This is a perfect example of undefined behavior. Which means that the behaviour of such code is not defined in the C Language, and the output can be anything, the program can print the old value of k it can print garbage, the program can crash, or an earthquake or alien invasion could occur. Note, because the behaviour is not defined, we cannot rule out earthquake or alien (also the 2012 deadline of Earth is approaching).

Undefined Behavior is defined in C99 standard Section 3.4.3 Paragraph 1 and 2. I am quoting Paragraph 1 below:

undefined behavior
behavior, upon use of a non-portable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements

If you compile this code with a good compiler it will also throw you a warning, like gcc does in my case:

t.c: In function ‘fun’:
t.c:18:5: warning: function returns address of local variable [enabled by default]

Explanation

First we need to understand lifetime or storage duration of a variable in C. Lifetime of a variable or an object is defined as the portion of the program during which storage is guaranteed to be reserved for the object. The storage duration related to an object/variable determines its lifetime. The Section 6.4.2 Paragraph 2 defines lifetime of a variable, which is quoted below.

The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

I think this paragraph explains it all.

k is automatic (local), therefore its lifetime will end whenever the block in which it is defined ends, which is actually the end of function fun (). The local variables k is allocated in the stack frame created for the function fun (). Whenever the function returns, the current active stack frame becomes the stack frame of the function main (), in this case, and the stack frame area of fun () is no more allocated, therefore the system can do whatever with it. Just because you are not doing anything, you can never assume that the stack frame of the last function call is unmodified. It can change in whatever manner, and therefore accessing any address location from that location can result in retrieval of the correct value, garbage value, pagefault or anything, which you can never tell definitely.

Therefore when the function fun () returns the address of the local variable k and it is assigned to the pointer variable j, also whenever the fun () returns, the lifetime of k is finished, and therefore its address location is not any more “guaranteed” to hold the “last-stored” value. The case of accessing the address location of k with *j falls exactly under the line “The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.” . This clearly indicates that the behaviour will be undefined.

One thing should be noted, it is immaterial if the automatic/local variables/objects are stored on the stack frame, and they may or may not be erased. If someone implements the function call in some other way and chooses some other place to allocate the local variables, then also the behaviour has to be the same as defined in the language definition.

You can run this code with a local k declaration in other compilers and will get different answer in different platforms and compilers.

Lifetime of automatic variables are defined in Section 6.2.4 Paragraph 5 and 6.

You can have a look at the entire Section 6.2.4 which contains the definitions about Storage Durations in C language.

This is the same cause for which you cannot return a local array.

If “k” was static

In the case k was defined as static the story would be something else. The code would have been perfectly all right, and a well defined behaviour, which is you will get the value last stored in the location. Why? This is to do with the lifetime of static variables. Static storage duration is defined in Section 6.2.4 Paragraph 3, which tells that the lifetime of a static variable/object is the entire execution of the program. Therefore the storage location of a static variable is guaranteed to be allocated throughout the execution of the program, therefore making it possible returning an address of a local static variable and use it without any problem. Similarly it will be same as the case of global variables, as they also have lifetime of the entire program.

Using address of local variable in a function call

Note that passing address of a local variable in a function call is perfectly all right. For example:

#include <stdio.h>

void fun (int *k);

int main (void)
{
  int j = 5;

  printf ("j = %d\n", j);
  fun (&j);
  printf ("j = %d\n", j);

  return 0;
}

void fun (int *k)
{
  *k = 10;
}

This will first print 5 and next 10. This is because when the function fun () is called the lifetime of j is not finished as the execution has not passed through the block in which j declared. From the other point of view the stackframe is preserved, and a new stackframe is created for fun ().

Advertisement

5 thoughts on “C Q&A #0: Returning address of local variable

  1. But the scope of a static variable is also local? How can we say that its memory location not destroyed when the function hands over the control to main?

    1. The *scope* of static local variable is inside the function, but its *lifetime* is throughout the entire runtime of the program execution. To support this statement I have included in the above text that this behaviour is mentioned in C99 Standard Section 6.2.4 Paragraph 3. I am quoting the paragraph below.

      the object it points to reaches the end of its lifetime. An object whose identifier is declared with external or internal linkage, or with the storage-class specifier static has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.
      

      This paragraph unambiguously states the behaviour, note the line “Its lifetime is the entire execution of the program … ” .

      Thanks for stopping by and asking the question!

  2. When we do the same thing without pointers… den wat?
    Like…

    int fun(int a){
     int s;
     s=a+a;
     return s;
    }
    

    And in the main..we have

    int main(){
     ...
     C=fun(10);
    printf("%d",C);
    printf("%d",C);
    ...
    }
    
    1. When you perform a return s;, this copies the value stored inside s into a temporary location (generally in a register), which will be accessed and copied to the variable C after the function call fun returns. Therefore this is safe, as the copied variable in C is just a value, and is not linked to something else.

      In case the value of s was an address local to fun, then it would have been a problem. This is because, upon return C will contain the address of something local to fun and upon the return the lifetime of the object related to that address has ended, so dereferencing C will lead to trouble.

      Bottom line: The code you have shown is perfect, and is an example of a normal function call.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s