1

Consider this little code

#include <stdio.h>
#include <stdlib.h>

void* foo1(double bar)
{
    double s2 = 0.5;
    double s1 = bar/s2;
    double toreturn[2] = {s1,s2};
    printf("Outside main. Second value: %f\n", toreturn[1]); //this line is commented out for the second output. See below text
    return toreturn;
}


int main()
{
    void* (*foo)(double) = NULL;
    foo = &foo1;
    double bar = 2.12;

    double* resp = foo(bar);
    printf("In main. First value: %f\n", resp[0]);
    printf("In main. Second value: %f\n", resp[1]);
    return 0;
}

The code outputs

Outside main. Second value: 0.500000
In main. First value: 4.240000
In main. Second value: 0.500000

, which is what I expected. However, if I comment out the the print instruction (the one within the definition of foo1), I get this output:

In main. First value: 4.240000
In main. Second value: 0.000000

, which makes no sense to me! It seems weird to me that a printf command can change the values of the variables. Can you explain please explain me this behavior?

Remi.b
  • 17,389
  • 28
  • 87
  • 168

2 Answers2

5

The main point here is that you cannot return a local array from the function. The memory that was used by array toreturn is free after the function call. It can be overwritten by any function call, including printf.

Use malloc to allocate memory for your array in the function and return a pointer to the allocated memory, or pass array as a parameter.

afenster
  • 3,468
  • 19
  • 26
  • ok, that makes sense. However I still don't really get why `printf` overwrite memory? – Remi.b Oct 28 '14 at 16:21
  • @Remi.b: After the function returns, the array no longer exists. In a typical implementation, the memory that was allocated for it still exists, but it's above the top of the stack. *Any* operation that uses the stack can reallocate the same memory and clobber its value. The behavior is undefined. – Keith Thompson Oct 28 '14 at 16:23
  • I suppose the compiler can just optimize out some assignment from your function as, if you remove printf, there is no sense in assigning any values to the array. Compare assembler code with and without printf, I suppose there will be a difference. Also, try to compile without any optimization. But anyway that's all wrong, it's undefined behavior and there is no sense trying to understand why it behaves this way or that. – afenster Oct 28 '14 at 16:26
  • In this particular case I would make the function accept two parameters, `double` and `double *`, and call it this way from main: `double arr[2]; func(d, arr);` so that you don't think about memory allocations at all. – afenster Oct 28 '14 at 16:32
2

You are returning a void* to an array that was allocated on the stack. Once the function foo1 returns, that memory is no longer allocated, and using resp from main is therefore undefined behaviour.

It makes no sense to print resp[0] or resp[1] and you shouldn't expect any particular output, since you have undefined behaviour.

If you want to use that array in main, you should declare it in main and pass a pointer to it as an argument to your function:

double resp[2];
foo(bar, resp);

With the function:

void foo1(double bar, double* resp)
{
    double s2 = 0.5;
    double s1 = bar/s2;

    resp[0] = s1;
    resp[1] = s2;
}

Alternatively you can allocate it inside foo1 with malloc and return a pointer to that allocated memory, but you'll need a good way of tracking every call to malloc, so that you can call free when you are done with it.

Paul
  • 139,544
  • 27
  • 275
  • 264