首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >直方图,频率计算

直方图,频率计算
EN

Stack Overflow用户
提问于 2013-10-02 21:14:34
回答 2查看 1.6K关注 0票数 0

我需要添加一个名为computeFrequencies的函数,给出一个有等级的数组,返回一个小数组,其中包含等级的频率分布。(这只是整个计划的一部分)

然而,我对c完全陌生,我不知道我做错了什么:给定错误:直方图2.c:16:10:错误:“等级”重新声明为不同类型的符号直方图2.c:15:29:注意:以前定义的‘年级’是在这里:直方图2.c:20:12:错误:订阅的值既不是数组,也不是指针,也不是向量

有谁可以帮我?非常感谢

代码语言:javascript
复制
void computeFrequencies(int grades[], int freq[10]){
int i, grades[];
int length=100;

for(i=0; i<length; i++){
 grades[i]=i;
 switch(i){
case 1: freq[1]++;
break;
case 2: freq[2]++;
break;
case 3: freq[3]++;
break;
case 4: freq[4]++;
break;
case 5: freq[5]++;
break;
case 6: freq[6]++;
break;
case 7: freq[7]++;
break;
case 8: freq[8]++;
break;
case 9: freq[9]++;
break;
default: freq[10]++;
}
}
}

嘿,谢谢你的回答,但即使我的错误消失了,我的程序也不起作用。我的程序需要显示特定等级频率的直方图。有谁可以帮我?

该输入文件名为1.in,包含: 29 6 3 8 7 4 8 9 2 10 5 4 6 7 7 7 2 10 4 1 8 8 3 3 6 6 9 4

我使用./a.out < 1.in来运行

产出应是:

代码语言:javascript
复制
. . . * . * . . . .
. . . * . * . * . .
. . * * . * * * * .
. * * * . * * * * *
* * * * * * * * * *
1 2 3 4 5 6 7 8 9 10

代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>

int *readGrades() {
int x, count;
    scanf("%d", &count);
int *grades = malloc(count * sizeof(int));
for (x = 0; x < count; ++x) {
    scanf("%d", &grades[x]);
}
return grades;
}

void computeFrequencies(int grades[], int freq[10]){
  int i;
   int length=100;

   for(i=0; i<length; i++){
     grades[i]=i;
     switch(i){
    case 1: freq[1]++;
    break;
    case 2: freq[2]++;
    break;
    case 3: freq[3]++;
    break;
    case 4: freq[4]++;
    break;
    case 5: freq[5]++;
    break;
    case 6: freq[6]++;
    break;
    case 7: freq[7]++;
    break;
    case 8: freq[8]++;
    break;
    case 9: freq[9]++;
    break;
    default: freq[10]++;
    }
  }
}

int arrayMax(int length, int arr[]) {
  int i, max = arr[0];
  for (i=1; i < length; i++) {
    if (arr[i] > max) {
      max = arr[i];
    }
  }
  return max;
}

void printHistogram(int freq[10]){
  int highestGrade = arrayMax(10,freq);
  int x;
  int y;

  for(x=highestGrade; x>0; x--) {
    for(y=1; y<=10; y++) {
      if(freq[y] < highestGrade && x > freq[y]) {
    if(y==10) {
      printf(".\n");
    }
    else {
      printf(". ");
    } 
      } else {
    if(freq[y] <= highestGrade && x <= freq[y]) {
      if(y==10) {
    printf("*\n");
      }
      else {
        printf("* ");
      }   
    }
      }
    }
  }
  printf("\n");
  printf("1 2 3 4 5 6 7 8 9 10\n");
}   



int main(int argc, char *argv[]) {
  int *grades;
  int frequencies[10];

  grades = readGrades();

  computeFrequencies(grades, frequencies);
  arrayMax(10,frequencies);
  printHistogram(frequencies);

  return 0;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-10-03 01:34:12

您的代码有几个问题,我将按外观顺序讨论它们。

首先,去掉“魔术数”常量--从上下文中看,这个意义并不明显(它们通常不是真正的常量)。例如,直方图(10)中的桶数。因此,我将使用一个符号常量NFREQ来引用数字10,它可以在包含之后使用预处理宏#define NFREQ 10来定义。

另一个神奇的数字是计算频率的函数中的100。除非我们将数字作为参数传递,否则无法确保数字是正确的。此问题会影响循环中使用的正确性,并保护对内存的访问。如果值太低,您将丢失一些数据。相反,如果值太高,则通过读取数组的末尾(通常显示为分段错误),得到未定义的行为。稍后我们将返回到这个函数。让我们先看看readGrades()

这是读取数据并存储输入的函数。这是您--在运行时--获取count参数的地方(我们在上面称为length )。在返回值时,还需要找到返回计数的方法。您可以将一个地址传递给将保存该值的变量。或者,您可以定义一个同时保存数据(年级)和长度的结构,并返回动态分配和填充的结构。因此,签名看起来可能类似于int *readGrades(int* cnt),并且在您设置的*cnt = count函数中。

反过来,computeFrequencies()现在使用一个额外的长度参数。通过将freq数组的长度作为另一个参数传递,可以使函数更通用。

代码语言:javascript
复制
void computeFrequencies(int grades[], int freq[], int grades_len){
    int i;

    memset(freq, 0, sizeof(freq[0])*NFREQ); // (!) init freq array

    for (i = 0; i < grades_len; ++i) {
        freq[grades[i]-1]++;
    }
}

不要忘记初始化freq数组。如果使用简单的printf循环打印中间结果,或者检查调试器中的值,则很容易捕获此bug。在这里,我假设等级来自范围[1..10],并且等级的总数相对较低,否则您将需要沿着y轴将其归一化到最大值。所以在这里,在简单的情况下,我们只是增加桶中的计数器,对应于等级数组中的每个级别。

此外,为了使代码更加健壮,您可以添加一些代码来验证用户输入(如果您键入一个字符而不是数字,会发生什么情况?)另外,您应该检查malloc没有返回NULL。如果是这样的话,您的程序就无法分配足够的内存,并且应该使用一个返回值来exit,返回值表示错误行为(例如,EXIT_FAILURE),并打印适当的错误消息通知用户。

如果给定的长度确实与数组的实际长度相匹配,那么arrayMax()函数似乎工作得很好(您可以使用前哨值 )。它返回最常见等级的最高频率。

打印直方图的功能可以首先校正,也可以稍微简化一些。一个问题是臭名昭著的越界访问( 10年级的频率存储在freq[9])。记住,C中的数组索引以0开头(因此是y < NFREQ,而不是<=)。代码的其余部分是自文档化的。

代码语言:javascript
复制
void printHistogram(int freq[]){
  int x, y, highestGrade = arrayMax(NFREQ, freq); 

  for (x = highestGrade; x > 0; --x) {
      for (y = 0; y < NFREQ; ++y) { 
          if (freq[y] >= x && x <= freq[y])
              printf("* ");
          else
              printf(". ");
          if (y == NFREQ-1)
              printf("\n");
      }
  }
  printf("1 2 3 4 5 6 7 8 9 10\n");
}

最后,您可以通过调用main显式释放以前不再需要的内存(在free(grades);中的返回语句之前)动态分配的内存来显示纪律和意识。在您的示例中,这并不是一个真正的问题,因为当主函数返回时,它将被隐式释放。

票数 1
EN

Stack Overflow用户

发布于 2013-10-02 21:15:46

删除重声明:

代码语言:javascript
复制
int i, grades[];
      ^^^^^^^^^
  • 附带注意:在函数声明中,int freq[10]具有误导性,因为它等同于int freq[]
  • 第二个注意事项:如果freq确实有10个元素长,那么freq[10]是超出界限的
  • 第三个注意:switch是无用的--您可以在确保i在一定范围内后直接使用它。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19146949

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档