【问题标题】:Totally unexpected output when trying to compute the average using arrays尝试使用数组计算平均值时完全出乎意料的输出
【发布时间】:2022-01-10 00:43:42
【问题描述】:

int 类型的文本文件中读取数据后,我试图计算平均值。程序编译得很好。 clang -std=gnu11 -Weverything -g3 -pedantic -g3 -O3 -lm average_weight_of_elephant_seals.c -o average_weight_of_elephant_seals

假设我想计算 2000 个印章的平均重量,预期输出是 6838.848152 但我得到 1710.566467。我还不知道如何理解 GDB。

谁能指出我哪里出错了?

/* The following program demonstrates the usage of fscan to read in a set of integer data into a file and then computes the sum followed by the average.
 * The computation shall be encapsulated in a function and then be called in the main routine
 */
#include <stdio.h>
#define MAXSIZE 5000 /* Macro definition to pre-define the size of the array */

double average_weight(int count, int weights_array[]);

int main(void)
{
    int number_of_seals;
    int weights_array[MAXSIZE];

    printf("Enter the number of seals: \n");
    scanf("%i", &number_of_seals);

    printf("Their average weight is %lf\n", average_weight(number_of_seals, &weights_array[number_of_seals]));

    return 0;
}

double average_weight(int count, int weights_array[])
{
    /* Variable declaration and initialization
     * Note the use of the FILE data type */
    int weight;
    int sum = 0;
    FILE *elephant_seal_data = fopen("elephant_seal_data.txt", "r");

    if (elephant_seal_data == NULL)
    {
        return -1;
    }

    /* FEOF function to determine if EOF has been reached or not */
    while (!feof(elephant_seal_data))
    {
        fscanf(elephant_seal_data, "%i", &weight);
        weights_array[count++] = weight;
        sum += weight;
        count++;
    }

    double average_weight = (double)sum / (double)count;
    fclose(elephant_seal_data);
    return average_weight;
}

【问题讨论】:

标签: arrays c function


【解决方案1】:
printf("Their average weight is %lf\n", average_weight(number_of_seals, &weights_array[number_of_seals]));

代码无缘无故地将指向某个位置的指针传递到数组中,并且不检查 number_of_seals * 2 是否小于 MAXSIZE,因此可能会溢出数组。但是这个计算无论如何都不需要数组。

    weights_array[count++] = weight;
    sum += weight;
    count++;

代码正在写入数组而不是读取它。此计算不需要数组。

代码增量计数两次,因此平均值将超出两倍,并且数组中的备用位置将具有未定义的值。

【讨论】:

  • 我忘了说这是一个赋值,我需要使用数组并将它传递给一个函数。
  • @AlokY 在这种情况下,您可能希望将问题分解,以便一个函数将文件中的数据读取到一个数组中,然后另一个函数计算该数组中的平均值。
  • 好的。我会试试看的。
【解决方案2】:

您的代码中有 2 个愚蠢的错误,一个更严重的错误,还有一个风险

首先是愚蠢的:

您将count 传递给函数根据文件中的每个值将该值增加两次。如果初始给定的值是正确的,那么您的计数会大 3 倍。您不应将count 传递给函数,而应在此处计算

你使用了错误的语法来传递一个数组:你应该传递一个指向它的第一个元素的指针。

现在是讨厌的一个:虽然Why is “while ( !feof (file) )” always wrong? 确实是一个常见问题解答,但在初学者代码中仍然很常见......

feof 仅在读取操作返回错误后返回 true。让我们检查最后一个值会发生什么。它被读取并正确处理一次。 feof 仍然返回 false (到目前为止没有错误),因此您的代码重新进入循环。 scanf 到达文件末尾并返回 0(您的代码忽略的内容)但不更改值 => 最后一个值将被处理两次。 永远不要使用while (!feof(...

最后是风险。

您正在将值求和为一个整数。即使平均值很容易适应那里,如果你有更大的值并且它们的数量非常多,你可能会得到一个整数溢出。将其汇总为更大类型(双精度?)的推荐方法,如果可能的话,使用 guess 来限制累积误差:average(qty-guess) + guess 确实是 average(quantity),但是计算的总和可以低得多,从而在使用浮点值时限制累积误差或在使用整数值时防止溢出。从密封的数量和预期的平均值来看,这里应该没有问题,所以猜测是没有用的,但请记住,对于不同的用例......

最后但同样重要的是,如果您不关心其他参数但从不 int main(void)

main 预计将被声明为 int main()

代码可能变成:

/* The following program demonstrates the usage of fscan to read in a set of integer data into a file and then computes the sum followed by the average.
 * The computation shall be encapsulated in a function and then be called in the main routine
 */
#include <stdio.h>
#define MAXSIZE 5000 /* Macro definition to pre-define the size of the array */

double average_weight(int* count, int weights_array[]);

int main()
{
    int number_of_seals;
    int weights_array[MAXSIZE];

    double weight = average_weight(&number_of_seals, weights_array);
    printf("Their number is %d and their average weight is %lf\n", number_of_seals, weight);

    return 0;
}

double average_weight(int* count, int weights_array[])
{
    /* Variable declaration and initialization
     * Note the use of the FILE data type */
    int weight;
    int sum = 0;
    FILE* elephant_seal_data = fopen("elephant_seal_data.txt", "r");

    if (elephant_seal_data == NULL)
    {
        return -1;
    }

    *count = 0;

    /* FEOF function to determine if EOF has been reached or not */
    for(int i=0; i<MAXSIZE; i++) // never process more than the array size
    {
        if (1 != fscanf(elephant_seal_data, "%i", &weight)) {
            break;    // immediately stop at end of file
        }
        weights_array[(* count)++] = weight;
        sum += weight;
    }

    double average_weight = (double)sum / (double)*count;
    fclose(elephant_seal_data);
    return average_weight;
}

我保持您的一般程序结构不变,但恕我直言,您应该首先将数据读入一个数组,然后将该填充的数组及其计数传递给一个平均函数。只需将您当前的功能分成 2 个步骤。

【讨论】:

  • 当我运行程序时,我得到Their number is 4199088 and their average weight is -1.000000
  • 我没有对您的错误处理进行任何更改。平均重量为 -1 意味着您无法打开(找到?)文件...
【解决方案3】:

您已发送要在数组中使用的计数数量,这很棒,因为该函数不知道 weights_array 的长度。但是你没有正确使用它。

我建议你:

  • 使用count 根据需要的数据量限制循环次数。
  • 不要更改/重新分配count 的值。因为这个数字对于计算平均值至关重要。创建一些其他变量来完成任务。

以下是我如何稍微修改您的代码以带来这些更改。我假设了elephant_seal_data.txt 的格式为空格分隔的整数值。

#include <stdio.h>
#define MAXSIZE 5000 /* Macro definition to pre-define the size of the array */

double average_weight(int count, int weights_array[]);

int main(void)
{
    int number_of_seals;
    int weights_array[MAXSIZE];

    printf("Enter the number of seals: \n");
    scanf("%i", &number_of_seals);

    printf("Their average weight is %lf\n", average_weight(number_of_seals, &weights_array[number_of_seals]));

    return 0;
}

double average_weight(int count, int weights_array[])
{
    /* Variable declaration and initialization
     * Note the use of the FILE data type */
    int weight;
    int sum = 0;
    int i = 0;
    FILE *elephant_seal_data = fopen("elephant_seal_data.txt", "r");

    if (elephant_seal_data == NULL)
    {
        return -1;
    }

    /* FEOF function to determine if EOF has been reached or not */
    while (i<count)
    {
        fscanf(elephant_seal_data, "%d", &weight);
        weights_array[i++] = weight;
        if (feof(elephant_seal_data)) break;
        sum += weight;
    }




    double average_weight = (double)sum / (double)count;
    fclose(elephant_seal_data);
    return average_weight;
}

编辑: 我已使用大象密封数据.txt 在 Google Colab 中为您模拟这些。尝试运行第一个单元格there

Google Colab Link

【讨论】:

  • 输出:Enter the number of seals: 2000 Their average weight is -1.000000
  • 您能否提供elephant_seal_data.txt 以便我检查格式并相应地匹配答案?而且我认为您的文件名有错字。或者它在错误的目录中。
  • 我已经进行了相应的编辑。现在尝试检查。此外,您可能想尝试使用 GoogleColab 链接在线运行代码。
  • 如果您的问题得到解答,请考虑这一点。 stackoverflow.com/help/someone-answers
猜你喜欢
  • 1970-01-01
  • 2020-07-25
  • 2021-12-08
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 1970-01-01
  • 2014-01-28
  • 2015-05-23
相关资源
最近更新 更多