2

This is a question from a C language course. Someone wants to return a value from a function with a pointer. He assigns the pointer address to result_ptr and prints this pointer's value.

When there is no Line A, printf() works fine: printf() prints 3.

However, when another addition() function is called in front of the printf(), something wrong happens: the printf() prints 5.

If Line A is commented out and Line B, another printf() function, is uncommented: the printf() prints 0.

What exactly is going on?

int *addition(int a, int b) {
    int d = a + b;
    int *c = &d;
    return c;
}

int main(int argc, const char * argv[])
{
    int *result_ptr = addition(1, 2);
    addition(2, 3); // Line A
//      printf("Another line\n"); // Line B
    printf("result = %d \n", *result_ptr);
    return 0;
}
Alfred Huang
  • 433
  • 6
  • 13

1 Answers1

5

When a function is called, the arguments (in reversed order), the return address and the Caller's EBP (which stores where the function returns to after execution) are pushed onto the stack. The callee setups a stack frame that stores its local variables and saves contents of 3 registers, EBX, ESI and EDI if they are modified. When the function finishes execution, the frame is popped and the stack's top returns to the height where it had been before the callee was called.

In this example, int *c declares a local pointer variable that is stored on the stack within the callee's frame. Returning that pointer is returning an address on the stack frame. As consecutive addition() calls cause identical stack space allocations, content of the same address will be written twice. This is why the second function call will write 5, overwriting 3 from the first function call: they are modifying the value at the same memory location. When printf() is called, however, the stack space is used for a totally different stack frame. Then the same location stores an undefined value.

To avoid this, it would be better to return a pointer to a location on the heap instead of on the stack. Mind to free the pointer after memory allocation to avoid leakage.

int *addition(int a, int b) {
    int *c = (int *) malloc(sizeof(int));
    *c = a + b;
    return c;
}

// in main
int *result_ptr=addition(1,2);
printf("value = %d \n",result_ptr);
free(result_ptr);
result_ptr=0;

Reference: http://www.csee.umbc.edu/~chang/cs313.s02/stack.shtml

I will be glad to see clearer or different explanations for this question.

Alfred Huang
  • 433
  • 6
  • 13
  • This is a good explanation. However, I believe it wouldn't hurt to be very explicit about the fact that returning a pointer to a local variable is always considered to be undefined behavior and must be avoided. (For an excellent treatment of the topic, see [the main answer to the question this is listed as "possibly a duplicate of"](http://stackoverflow.com/a/6445794/2171689).) – This isn't my real name Sep 15 '14 at 20:40