2

I have some C code that essentially looks something like

double* my_function(double* input) {
    double* output = (double*) malloc(...);
    // Do some stuff to output based on input
    return output;
}

Assuming that I have already built an array called my_var_in, my main code has something like

double* my_var_out = my_function(my_var_in);

This creates new memory, which my_var_out points to; most of the time that's exactly what I want to happen. However, sometimes I just want to update the already existing memory. If I write

double* my_var = ... ; // allocate and fill my_var as desired
my_var = my_function(my_var);

Then I lose the pointer to the previously existing memory since my_var now points to the newly allocated memory. I've played around with several different ideas for how to get around this.

1) I know I can get this to work by changing the function style to something like

void my_function(double* destination, double* source) {
    // Check if destination == source and update based on this

I've previously developed with this style of passing the destination pointer as an input argument and updating it there; it works great functionally, but I like the style of outputting pointers better and want to keep developing with it.

2) Based on here and here, it seems that the __builtin_return_address function could be of some use. I think I can use this function to compare the input address with the output address and allocate/update based on that. After reading the documentation here, I wrote the following test

int* just_testing(int* in) {
    void* ptr = __builtin_return_address(0); // the return address of just_testing
    printf("Input address: %p\n", in);
    printf("From function: %p\n", ptr);

    return in;
}

int main(int argc, char** argv) {

    int* out = (int*) malloc(sizeof(int));
    out[0] = 2;
    printf("From main before call: %p\n", out);
    out = just_testing(out);
    printf("From main after call: %p\n", out);

    return 0;
}

This gives me the output

From main before call: 0x19b2010
Input address: 0x19b2010
From function: 0x4011f1
From main after call: 0x19b2010

Unfortunately, the results from __builtin_return_address don't match the address of the variable that receives the return from the function, which I did not expect.

Why aren't the addresses the same? I also welcome any constructive suggestions on a different approach besides the two I've listed here.

KindaTechy
  • 1,041
  • 9
  • 25
  • That's not what "return address" means, and what you want is impossible, sorry. Just continue passing the destination pointer as an argument; it's quite standard. – Ry- Nov 23 '16 at 05:25
  • After trying out a few different implementations, it seems like this really is the best way to accomplish what I want. Thanks for the advice. – KindaTechy Nov 29 '16 at 00:44

2 Answers2

1

The cleanest solution is to have two separate functions:

#include <stdlib.h>
#include <string.h>

void compute_inplace(double *data) {
    data[0] *= 2;
}

double *compute_copying(const double *input) {
    double *output = malloc(sizeof *output * N);
    if (output == NULL)
        return NULL;

    memcpy(output, input, sizeof *output * N);
    compute_inplace(output);
    return output;
}

Note that the copying function takes its argument as a pointer to const, which helps if you accidentally pass a read-only memory area to it.

Roland Illig
  • 40,703
  • 10
  • 88
  • 121
  • 2
    I think that the second function should still return the pointer. Apart from that two functions is the best solution because it is known at compile time what the programmer wants. – Peter - Reinstate Monica Nov 23 '16 at 06:34
0

Other possible solution could be to have following definition:-

double* my_function(double* input, bool alloc)
{
   double* output = input;

   if(alloc)
   {
       //allocate new memory
       double* output = ( double*)malloc(...);
   }
   //else work with input memory

   //do modifications here

   return output;
}
MGpro
  • 33
  • 4
  • Good suggestion. I just implemented it and included varargs so that it only needs the extra argument if it is updating. Still not as clean as I would like, and there's still a possibility of losing the pointer. – KindaTechy Nov 23 '16 at 20:57