如何从一个函数返回两个值?

18

可能是重复问题:
从函数返回多个值

假设我向一个函数iCalculate(int x, int y)传递了两个值,并且这个iCalculate函数返回两个值,它们分别是:

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

现在我应该如何通过同一个函数同时返回上述两个值?

我的方法是:

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

你有什么问题? - Andrew Anderson
5个回答

29

返回本地数组第一个元素的地址具有未定义行为(至少稍后解引用它时是如此)。

您可以使用输出参数,也就是传递两个指针,并在内部设置值。

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

用法:

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

你可以做的另一件事是将你的数据打包到一个结构体中。

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;
}

12
但对于返回struct选项,我的速度并不比我快。C程序员为什么总是先考虑指针解决方案,而将简单的解决方案放在第二位呢?;) - Fred Foo
因为返回/传递结构体意味着复制所有结构体元素。这就是为什么我建议第三种解决方案:返回/传递指向结构体的指针 :-) - dragon135
@larsmans:不需要 - 结构体指针将使用正常的ABI调用约定(可能在寄存器中)传递和返回,原始结构体可以在堆栈上。 - DaveR
2
@Dave:只有当你通过指针传递 struct,使客户端负责分配内存时才会出现这种情况。让我们看看我们能得到什么:我们不再复制两个32位整数,而是仅复制单个32位指针。并且这只需要额外的一个声明、一个 & 操作符和两个解引用。不,等等,32位指针?那是昨天年代的硬件了... - Fred Foo
1
@dragon135:扩展struct是一个有效的观点,但不适用于这种数学函数,因为你知道将返回什么。 - Fred Foo
显示剩余6条评论

11

那样是行不通的,因为你返回了一个指向临时数组的指针,在函数返回时会停止存在。

相反,定义

typedef struct { int first, second; } IntPair;

并返回该类型的一个对象。

(这就是标准库函数 divldiv 所做的事情,只不过它们以不同的方式调用该类型。)


有没有一个函数可以包含多个返回类型? - Abhineet
3
首先是 divldiv。大多数其他函数都通过指针返回,尽管在现代计算机上这并不是必要的(它曾经是一种优化方法)。 - Fred Foo

2
您的方法不正确,当函数iCalculate结束时,temp已经超出了其作用域或不存在。因此,您不应该返回temp的地址。这将是一个超出作用域或不存在变量的地址。访问该地址意味着未定义的行为。
您可以尝试以下方法:
void iCalculate(int x,int y,int *mult,int *divi){
   *mult = x*y;
   *divi = x/y;
}

或者你可以采用另一种方法:
typedef struct{ 
   int mul, divi;
} TResult;

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

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

我建议采用第一种方法。我认为创建一个新的结构体定义只是为了将两个不相关的值封装在一起太傻了。


不一定会被销毁,但会引发未定义行为。众所周知,当函数退出时,栈不会用零填充。抱歉,我只是有点追求严谨 ;) - new123456
我只是使用了逻辑上的词语。更正确的术语应该是变量超出了作用域。在 C 语言中,没有任何东西被销毁,即使从堆中释放也不会填充为零。 - dragon135

1
你的方法是错误的,因为一旦函数返回,int temp[2] 就会消失,所以调用者会有一个“悬空”的指针。你必须添加 static。另一种更好的方式是让调用者传递它想要存储结果的位置。
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.
}

而调用者将会执行类似的操作

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

或类似。


1

你的方法不是完全错误的,你可以这样返回表的地址:

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

别忘了释放内存:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接