如何从C中的函数返回多个类型?

时间:2017-08-03 14:31:07

标签: c function struct return-value

我在C中有一个函数来计算数组的平均值。在同一个循环中,我创建了一个t值数组。我当前的函数返回平均值。如何修改它以返回t数组?

/* function returning the mean of an array */
double getMean(int arr[], int size) {
   int i;
   printf("\n");
   float mean;
   double sum = 0;
   float t[size];/* this is static allocation */
    for (i = 0; i < size; ++i) {
        sum += arr[i];
        t[i] = 10.5*(i) / (128.0 - 1.0);
        //printf("%f\n",t[i]);
   }
   mean = sum/size;
   return mean;
}

思想: 我是否需要在函数中定义结构?这适用于类型标量和类型数组吗?有没有更简洁的方法呢?

3 个答案:

答案 0 :(得分:4)

您只能在C函数中返回1个对象。因此,如果您无法选择,那么您必须制作一个结构来返回您的2个值,例如:

typedef struct X{
     double mean;
     double *newArray;
} X;

但是,在您的情况下,您还需要使用t动态分配malloc,否则返回的数组将在堆栈中丢失。

另一种方法是让调用者分配新数组,并将其作为指针传递给你,这样,你仍然只返回均值,并用你的计算值填充给定的数组。

答案 1 :(得分:3)

对于类似这样的事情,最常见的方法是让调用者为您想要返回的值提供存储空间。你可以为你的函数添加t另一个参数:

double getMean(double *t, const int *arr, size_t size) {
   double sum = 0;
   for (size_t i = 0; i < size; ++i) {
        sum += arr[i];
        t[i] = 10.5*(i) / (128.0 - 1.0);
   }
   return sum/size;
}

此片段还改进了其他一些方面:

  • 请勿使用float,尤其是在您打算返回double时。 float的精确度很差
  • 使用size_t表示对象大小。虽然int经常有效,但size_t可保证保留任何可能的对象大小并且是安全的选择
  • 不要在计算某事的函数中混合输出(只是风格建议)
  • 声明变量靠近它们首先使用的位置(另一种风格建议)
  • 这有点自以为是,但我改变了你的签名,使其明确地将函数传递给指向数组的指针,而不是数组。在C中传递数组是不可能的,因此具有数组类型的参数会自动调整为相应的指针类型。
  • 由于您不打算修改arr指向的内容,请通过添加const使其明确。这有助于例如编译器在您不小心尝试修改此数组时捕获错误。

您可以调用此代码,例如像这样:

int numbers[] = {1, 2, 3, 4, 5};
double foo[5];

double mean = getMean(foo, numbers, 5);

而不是幻数 5,您可以编写例如sizeof numbers / sizeof *numbers

另一种方法是在函数内部使用malloc()动态分配数组,但这需要调用者稍后free()。哪种方法更合适取决于您的其他程序。

答案 2 :(得分:2)

遵循@FelixPalmen建议的建议可能是最好的选择。但是,如果存在可以预期的最大数组大小,则还可以将数组包装在struct中,而无需动态分配。这允许代码在不需要重新分配的情况下创建新的struct

可以在mean_array函数中创建get_mean()结构,分配正确的值,并返回到调用函数。调用函数只需要提供mean_array结构来接收返回的值。

#include <stdio.h>
#include <assert.h>

#define MAX_ARR  100

struct mean_array {
    double mean;
    double array[MAX_ARR];
    size_t num_elems;
};

struct mean_array get_mean(int arr[], size_t arr_sz);

int main(void)
{
    int my_arr[] = { 1, 2, 3, 4, 5 };

    struct mean_array result = get_mean(my_arr, sizeof my_arr / sizeof *my_arr);

    printf("mean: %f\n", result.mean);
    for (size_t i = 0; i < result.num_elems; i++) {
        printf("%8.5f", result.array[i]);
    }
    putchar('\n');

    return 0;
}

struct mean_array get_mean(int arr[], size_t arr_sz)
{
    assert(arr_sz <= MAX_ARR);
    struct mean_array res = { .num_elems = arr_sz };
    double sum = 0;

    for (size_t i = 0; i < arr_sz; i++) {
        sum += arr[i];
        res.array[i] = 10.5 * i / (128.0 - 1.0);
    }
    res.mean = sum / arr_sz;

    return res;
}

节目输出:

mean: 3.000000
0.00000 0.08268 0.16535 0.24803 0.33071

回答OP在评论中提出的几个问题:

size_t是用于数组索引的正确类型,因为它保证能够保存任何数组索引。您通常可以使用int来逃避;但是要小心,因为在数组的第一个元素之前访问或者甚至形成指向位置的指针会导致未定义的行为。通常,数组索引应该是非负的。此外,size_t在某些实现中可能比int更宽泛; size_t保证保留任何数组索引,但int没有这样的保证。

关于此处使用的for循环语法,例如,for (size_t i = 0; i < sz; i++) {}:此处i声明为循环范围。也就是说,当退出循环体时,i的生命周期结束。这是自C99以来的可能。最好在可能的情况下限制变量范围。我默认这样做,所以我必须主动选择以使循环变量在循环体之外可用。

如果循环范围的变量或size_t类型导致编译错误,我怀疑您可能正在以C89模式进行编译。这两个功能都是在C99中引入的。如果您使用的是gcc,旧版本(例如,gcc 4.x,我相信)默认为C89。您可以使用gcc -std=c99gcc -std=c11进行编译,以使用更新的语言标准。我建议至少启用警告:gcc -std=c99 -Wall -Wextra以便在编译时捕获许多问题。如果您在Windows中工作,您可能也遇到类似的困难。据我了解,MSVC符合C89标准,但对后来的C语言标准的支持有限。

相关问题