18

Possible Duplicate:
returning multiple values from a function

Suppose i have passed two values to a function iCalculate(int x, int y) and this iCalculate returns two values. Those are as follows:-

  • (x*y)
  • (x/y)

Now how should i return the above two values at the same time with the same function?

My Approach was:-

int* iCalculate(int x,int y){
   int temp[2];
   temp[0] = x*y;
   temp[1] = x/y;
   return temp;
}
Kalana
  • 5,631
  • 7
  • 30
  • 51
Abhineet
  • 6,459
  • 10
  • 35
  • 53

5 Answers5

29

returning the address of the first element of a local array has undefined behavior(at least dereferencing it later is).

You may use output parameters, that is, pass two pointers, and set the values inside

void Calculate(int x, int y, int* prod, int* quot)
{
    *prod = x*y;
    *quot = x/y;
}

usage:

int x = 10,y = 2, prod, quot;
Calculate(x, y, &prod, &quot)

Another thing you could do is pack your data into a struct

typedef struct 
{
    int prod;
    int quot;
} product_and_quot;


product_and_quot Calculate(int x, int y)
{
    product_and_quot p = {x*y, x/y};
    return p;
}
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • 12
    But not faster than me for the `struct` return option. What is it with C programmers that they always think of the pointer solution first, and the easy solution second? ;) – Fred Foo Jul 16 '11 at 11:33
  • Because returning/passing struct means copying all struct elements. That's why I suggest 3rd solution: returning/passsing pointer to the struct :-) – dragon135 Jul 16 '11 at 11:42
  • Returning a local array and then de-referncing it externally will surely fail eventually if not right away, it's just a matter of time until the stack climbs up high enough to destroy that data. – Peter Jul 16 '11 at 11:56
  • @dragon135: we're talking about two `int`s here. If you return a pointer to a `struct`, you have to allocate it on the heap. – Fred Foo Jul 16 '11 at 11:59
  • @larsmans: No you don't - the pointer to the struct would be passed and returned using normal ABI calling conventions (probably in a register), and the original struct could be on the stack. – DaveR Jul 16 '11 at 12:06
  • 2
    @Dave: only if you pass the `struct` *in* by pointer, i.e. make the client responsible for allocating it. Let's see what we've gained then: we're not copying two 32-bit ints anymore, instead we're copying just a single 32-bit pointer. And it only took an extra declaration, an `&` operator and two dereferences. No, wait, 32-bit pointers, that was on yesteryear's hardware... – Fred Foo Jul 16 '11 at 12:46
  • @larsmans: What if the code evolves. What happens if you always use create and copy approach. Unintended side effects. What if your struct growss to contain many fields, arrays, nested structs. What values you assign to each field of the struct you created in a function that is just interested to 1 or 2 of the fields? The point is that passing pointer of the struct will save you possible copying overhead in the future if your struct 'grows' and also allow for future extension to the struct without you having to modify your Calculate function to add correct initialization to every other field. – dragon135 Jul 16 '11 at 13:41
  • @larsmans: I'm not suggesting you would use a struct (in fact I think the individual out params is generally a better solution) - I'm just pointing out your assertion that you *have* to allocate on the heap is false. – DaveR Jul 16 '11 at 16:21
  • There are two more commonly-used variants, though they are somewhat cumbersome to do in C: You can return a closure which can be called with the kind of value you're interested in when you need it (if some of the values are seldom used and take a long time to calculate, this kind of lazy evaluation can be of value), and you can pass callback functions taking the results instead of the "out" parameters, with the idea that you only specify those callbacks which take values you are interested in, and the function skips calculation of results you didn't pass a callback for (or rather, passed NULL) – Martin Sojka Jul 17 '11 at 07:42
  • 1
    @dragon135: growing the `struct` is a valid point, but not for this kind of mathematical function, where you know what will be returned. – Fred Foo Jul 17 '11 at 13:21
  • @larsmans I agree with Dave Rigby that for this problem the individual out params is a better solution than creating a meaningless struct just to wrap those 2 'unrelated' result. – dragon135 Jul 18 '11 at 05:08
11

That won't work, since you're returning a pointer to a temporary array, which will stop existing at function return time.

Instead, define

typedef struct { int first, second; } IntPair;

and return an object of that type.

(This is what the standard library functions div and ldiv do, except that they call the type differently.)

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Is there any function which consist of more than one return type? – Abhineet Jul 16 '11 at 11:33
  • 3
    `div` and `ldiv`, foremost. Most others return by pointer, though that's not really necessary on modern machines (it used to be an optimization). – Fred Foo Jul 16 '11 at 11:34
2

Your approach is wrong, temp is out of scope/ not longer exist when functon iCalculate exit. So you must not return the address of temp. That would be address of out of scope/ no longer exist variable. Accessing that address means undefined behaviour.

You can use this approach:

void iCalculate(int x,int y,int *mult,int *divi){
   *mult = x*y;
   *divi = x/y;
}

or you can use another approach:

typedef struct{ 
   int mul, divi;
} TResult;

TResult iCalculate(int x,int y){
   TResult res;
   res.mul = x*y;
   res.divi = x/y;
   return res;
}

or :

void iCalculate(int x,int y,TResult *res){
   res->mul = x*y;
   res->divi = x/y;
}

I suggest the first approach. I think it is too silly to create a new struct definition only to wrap 2 unrelated value together.

dragon135
  • 1,366
  • 8
  • 19
  • Not necessarily destroyed, but it invokes Undefined Behavior. As we all know, the stack isn't padded with zeroes when the function exits. Sorry, I just had to be a little pendantic ;) – new123456 Jul 16 '11 at 17:08
  • I was just using logical word. The more correct term would be that the variable is out of scope. Nothing is destroyed in C, even freeing from heap doesn't pad it with zero. – dragon135 Jul 18 '11 at 05:37
1

The way you did is wrong since int temp[2] disappears once the function returns, so the caller has a "dangling" pointer. You have to add static. Another way, likely better, is to let the caller pass where it wants the result be store e.g.

void iCalc(int x, int y, int *rp, int *rq)
{
   // check if rp and rq are NULL, if so, returns
   *rp = x*y;
   *rq = x/y; // y != 0, and this will truncate of course.
}

and the caller will do something like

int res[2];
iCalc(x, y, res, res+1);

or similar.

ShinTakezou
  • 9,432
  • 1
  • 29
  • 39
1

Your approach was not so wrong you can return the address of the table like this :

int *iCalculate(int x,int y){
    int *temp=malloc(sizeof(int)*2);
    temp[0]=x*y;
    temp[1]=x/y;
    return temp;
}

dont forget to free the memory :

int *result;
result=iCalculate(10,7);
printf("%d %d\n",result[0],result[1]);
free(result);
cendar
  • 34
  • 3