首页 > 解决方案 > 取使用动态创建的数组生成的数字的平均值

问题描述

我基本上必须制作一个程序来接受输入,根据输入分配足够的内存,动态分配该大小的整数数组,并找到它们的平均值。示例输入:

Enter the number of integers: 5
0 1 2 3 4
average: 2

到目前为止,使用我拥有的代码,我已经完成了第一部分,但无法弄清楚如何找到从输入中获得的数字的平均值。我已经阅读了我的笔记,甚至在谷歌上搜索了类似的解决方案,但什么也没得到。这是我到目前为止的代码:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int* myData = NULL;
    int numData;
    int i;
    double average;

    printf("Enter the number of integers: ");

    scanf("%d", &numData);

    myData = (int*)malloc(numData * sizeof(int));


    for(i = 0; i < numData; ++i)
    {
      printf("%d ", i); 
              
        
    }

    printf("\n");
    
for(i = 0; i < numData; i++)
{
    average += myData[i];
}

printf("average: %lf", average);

   

    free(myData);

    return 0;

    


}

这是我得到的输出:

Enter the number of integers: 5
0 1 2 3 4 
average: 1215569347.000000

关于我做错了什么的任何想法?

标签: arrayscaverage

解决方案


除了未初始化average以及您没有填充myData任何数据的事实(导致每次添加不确定值的相同问题)之外,您对单个非数字的错误输入时的未定义行为average敞开大门键(就像用户伸手去拿但轻敲...)'6''t'

您必须通过检查使用代码中的值之前使用的输入函数的返回来验证每个用户输入......并且......您必须在使用指向内存块的指针之前验证每个分配。这不是“如果” malloc()失败的问题,而是“何时” malloc()失败的问题。

此外,您可能希望在代码中为中间步骤提供更具描述性的名称。例如,您正在计算的sum不是平均值:

average += myData[i];

平均计算稍后出现。中间变量名称sum会说明这一点。(在短代码中很明显,您average在除以numData计算最终平均值之前正在构建总和 - 但是学习好习惯比以后改掉坏习惯要容易得多)

最后,由于您在整数类型中对相当大的整数值求和,因此在实际对数字求和之前检查加法中的溢出。可以通过包含limits.hforINT_MAXINT_MINthen 来编写快速溢出测试:

#include <limits.h>

int addoverflow (int a, int b)
{
    if ((a > 0 && b > INT_MAX - a) ||
        (a < 0 && b < INT_MIN - a))
        return 1;
    
    return 0;
}

1如果发生溢出或0不发生溢出,它只会返回。

用户输入的最小验证

要使用 最小化验证用户输入scanf,您必须检查返回是否等于请求的转换次数(转换计数)。例如numData,您可以执行以下操作:

    printf("Enter the number of integers: ");

    if (scanf ("%d", &numData) != 1) {  /* validate EVERY user-input */
        fputs ("error: invalid integer input.\n", stderr);
        return 1;
    }

但是由于您将用作计算numData中的除数average,因此您必须确保它不为零(并且您不能有负数),因此也是非负数。换句话说,您还必须验证用户输入的范围以确保其有效。您可以通过以下方式简单地做到这一点:

    if (numData < 1) {  /* validate range of all inputs where needed */
        fputs ("error: input must be greater than 0.\n", stderr);
        return 1;
    }

注意:这些是最低限度的验证。您最终希望优雅地处理输入中的错误,捕捉错误,从输入缓冲区中清除任何有问题的字符stdin,然后让用户有机会更正——但现在您必须至少提供避免未定义行为浮点异常的最少验证)

验证分配

如上所述,这不是“如果”的问题,而是“何时”malloc失败的问题。现在有了一些简单的例子,失败的可能性很小,但这并不会改变您验证分配成功的责任。同样,您只需检查 returnmalloc()失败返回NULL。你可以做:

    /* validate EVERY allocation */
    if (!(myData = malloc(numData * sizeof *myData))) {
        perror ("malloc-myData");
        return 1;
    }

注意:在 C 中,不需要强制转换的返回malloc,没有必要。请参阅:我是否强制转换 malloc 的结果?。此外,建议您使用取消引用的指针来设置类型大小而不是文字类型。像int这样的基本类型通常不是问题,但是在为聚合类型分配时,或者为具有多个间接级别的指针分配时,很容易出错)

总而言之

把它放在一个简短的例子中,包括使用描述性中间sum,你可以这样做:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int addoverflow (int a, int b)
{
    if ((a > 0 && b > INT_MAX - a) ||
        (a < 0 && b < INT_MIN - a))
        return 1;
    
    return 0;
}

int main(void)
{
    int *myData = NULL,
        numData,
        sum = 0;
    double average = 0;

    printf("Enter the number of integers: ");

    if (scanf ("%d", &numData) != 1) {  /* validate EVERY user-input */
        fputs ("error: invalid integer input.\n", stderr);
        return 1;
    }
    if (numData < 1) {  /* validate range of all inputs where needed */
        fputs ("error: input must be greater than 0.\n", stderr);
        return 1;
    }
    
    /* validate EVERY allocation */
    if (!(myData = malloc(numData * sizeof *myData))) {
        perror ("malloc-myData");
        return 1;
    }

    for(int i = 0; i < numData; ++i) {
        printf ("myData[%2d] : ", i);
        if (scanf ("%d", &myData[i]) != 1) {    /* validate! */
            fputs ("error: invalid integer input.\n", stderr);
            return 1;
        }
        if (addoverflow (sum, myData[i])) {     /* check overflow in addition */
            fputs ("error: overflow in addition.\n", stderr);
            return 1;
        }
        sum += myData[i];               /* now sum data */
    }
    average = (double)sum / numData;    /* take average */
    
    printf ("\nsum    : %d\naverage: %lf\n", sum, average);

    free(myData);       /* free allocated memory */
}

注意:不需要'\n'单独调用来输出单曲printf(),如果需要单曲'\n',则输出单字符的正确方法是使用 with putchar()

示例使用/输出

$ ./bin/avgdata
Enter the number of integers: 5
myData[ 0] : 13243360
myData[ 1] : 13243364
myData[ 2] : 13243368
myData[ 3] : 13243372
myData[ 4] : 13243376

sum    : 66216840
average: 13243368.000000

故意溢出:

$ ./bin/avgdata
Enter the number of integers: 5
myData[ 0] : 513243360
myData[ 1] : 513243364
myData[ 2] : 513243368
myData[ 3] : 513243372
myData[ 4] : 513243376
error: overflow in addition.

如果您还有其他问题,请仔细查看并告诉我。学习处理代码中的错误并避免未定义行为对于正确处理代码逻辑同样重要。如果其中任何一个没有正确处理——可能会导致垃圾输出(或段错误)。


推荐阅读