简体   繁体   English

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

[英]How to return multiple types from a function in C?

I have a function in C which calculates the mean of an array. 我在C中有一个函数来计算数组的平均值。 Within the same loop, I am creating an array of t values. 在同一个循环中,我创建了一个t值数组。 My current function returns the mean value. 我当前的函数返回平均值。 How can I modify this to return the t array also? 如何修改它以返回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;
}

Thoughts: Do I need to define a struct within the function? 想法:我需要在函数中定义一个结构吗? Does this work for type scalar and type array? 这适用于类型标量和类型数组吗? Is there a cleaner way of doing this? 这样做有更干净的方法吗?

You can return only 1 object in a C function. 您只能在C函数中返回1个对象。 So, if you can't choose, you'll have to make a structure to return your 2 values, something like : 所以,如果你不能选择,你必须建立一个结构来返回你的2个值,如:

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

BUT, in your case, you'll also need to dynamically allocate the t by using malloc otherwise, the returned array will be lost in stack. 但是,在您的情况下,您还需要使用malloc动态分配t ,否则返回的数组将在堆栈中丢失。

Another way, would be to let the caller allocate the new array, and pass it to you as a pointer, this way, you will still return only the mean, and fill the given array with your computed values. 另一种方法是让调用者分配新数组,并将其作为指针传递给你,这样,你仍然只返回均值,并用你的计算值填充给定的数组。

The most common approach for something like this is letting the caller provide storage for the values you want to return. 对于类似这样的事情,最常见的方法是让调用者为您想要返回的值提供存储空间。 You could just make t another parameter to your function for that: 你可以只让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;
}

This snippet also improves on some other aspects: 此片段还改进了其他一些方面:

  • Don't use float , especially not when you intend to return a double . 不要使用float ,特别是当你打算返回double float时。 float has very poor precision float精度很差
  • Use size_t for object sizes. 使用size_t作为对象大小。 While int often works, size_t is guaranteed to hold any possible object size and is the safe choice 虽然int经常工作,但size_t保证保持任何可能的对象大小,是安全的选择
  • Don't mix output in functions calculating something (just a stylistic advice) 不要在计算某事的函数中混合输出(只是风格建议)
  • Declare variables close to where they are used first (another stylistic advice) 声明变量接近它们首先使用的位置(另一种风格建议)
  • This is somewhat opinionated, but I changed your signature to make it explicit the function is passed pointers to arrays, not arrays. 这有点自以为是,但我改变了你的签名,使其明确地将函数传递给指向数组的指针,而不是数组。 It's impossible to pass an array in C, therefore a parameter with an array type is automatically adjusted to the corresponding pointer type anyways. 在C中传递数组是不可能的,因此具有数组类型的参数无论如何都会自动调整为相应的指针类型。
  • As you don't intend to modify what arr points to, make it explicit by adding a const . 由于您不打算修改arr指向的内容,因此通过添加const使其显式化。 This helps for example the compiler to catch errors if you accidentally attempt to modify this array. 这有助于例如编译器在您不小心尝试修改此数组时捕获错误。

You would call this code eg like this: 您可以像这样调用此代码:

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

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

instead of the magic number 5 , you could write eg sizeof numbers / sizeof *numbers . 而不是幻数 5 ,你可以写出例如sizeof numbers / sizeof *numbers


Another approach is to dynamically allocate the array with malloc() inside your function, but this requires the caller to free() it later. 另一种方法是在函数内部使用malloc()动态分配数组,但这需要调用者稍后free() Which approach is more suitable depends on the rest of your program. 哪种方法更合适取决于您的其他程序。

Following the advice suggested by @FelixPalmen is probably the best choice. 遵循@FelixPalmen建议的建议可能是最好的选择。 But, if there is a maximum array size that can be expected, it is also possible to wrap arrays in a struct , without needing dynamic allocation. 但是,如果存在可以预期的最大数组大小,则还可以在struct包装数组,而无需动态分配。 This allows code to create new struct s without the need for deallocation. 这允许代码创建新的struct而无需重新分配。

A mean_array structure can be created in the get_mean() function, assigned the correct values, and returned to the calling function. 可以在get_mean()函数中创建mean_array结构,分配正确的值,并返回到调用函数。 The calling function only needs to provide a mean_array structure to receive the returned value. 调用函数只需要提供一个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;
}

Program output: 节目输出:

mean: 3.000000
0.00000 0.08268 0.16535 0.24803 0.33071

In answer to a couple of questions asked by OP in the comments: 回答OP在评论中提出的几个问题:

size_t is the correct type to use for array indices, since it is guaranteed to be able to hold any array index. size_t是用于数组索引的正确类型,因为它保证能够保存任何数组索引。 You can often get away with int instead; 你可以经常使用int来逃避; be careful with this, though, since accessing, or even forming a pointer to, the location one before the first element of an array leads to undefined behavior. 但是要小心,因为在数组的第一个元素之前访问或者甚至形成指向位置的指针会导致未定义的行为。 In general, array indices should be non-negative. 通常,数组索引应该是非负的。 Further, size_t may be a wider type than int in some implementations; 此外,在一些实现中, size_t可以是比int更宽的类型; size_t is guaranteed to hold any array index, but there is no such guarantee for int . size_t保证保存任何数组索引,但int没有这样的保证。

Concerning the for loop syntax used here, eg, for (size_t i = 0; i < sz; i++) {} : here i is declared with loop scope . 关于这里使用的for循环语法,例如, for (size_t i = 0; i < sz; i++) {} :这里i循环范围声明。 That is, the lifetime of i ends when the loop body is exited. 也就是说,当循环体退出时, i的寿命结束。 This has been possible since C99. 这是自C99以来的可能。 It is good practice to limit variable scopes when possible. 最好在可能的情况下限制变量范围。 I default to this so that I must actively choose to make loop variables available outside of loop bodies. 我默认这样做,所以我必须主动选择在循环体外部提供循环变量。

If the loop-scoped variables or size_t types are causing compilation errors, I suspect that you may be compiling in C89 mode. 如果循环范围的变量或size_t类型导致编译错误,我怀疑您可能正在以C89模式进行编译。 Both of these features were introduced in C99.If you are using gcc, older versions (for example, gcc 4.x, I believe) default to C89. 这两个功能都是在C99中引入的。如果您使用的是gcc,旧版本(例如,gcc 4.x,我相信)默认为C89。 You can compile with gcc -std=c99 or gcc -std=c11 to use a more recent language standard. 您可以使用gcc -std=c99gcc -std=c11进行编译,以使用更新的语言标准。 I would recommend at least enabling warnings with: gcc -std=c99 -Wall -Wextra to catch many problems at compilation time. 我建议至少启用警告: gcc -std=c99 -Wall -Wextra在编译时捕获许多问题。 If you are working in Windows, you may also have similar difficulties. 如果您在Windows中工作,您可能也遇到类似的困难。 As I understand it, MSVC is C89 compliant, but has limited support for later C language standards. 据我了解,MSVC符合C89标准,但对后来的C语言标准的支持有限。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM