我在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;
}
思想: 我是否需要在函数中定义结构?这适用于类型标量和类型数组吗?有没有更简洁的方法呢?
答案 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
可保证保留任何可能的对象大小并且是安全的选择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=c99
或gcc -std=c11
进行编译,以使用更新的语言标准。我建议至少启用警告:gcc -std=c99 -Wall -Wextra
以便在编译时捕获许多问题。如果您在Windows中工作,您可能也遇到类似的困难。据我了解,MSVC符合C89标准,但对后来的C语言标准的支持有限。