【问题标题】:Histogram, the computing of frequencies直方图,频率的计算
【发布时间】:2013-10-09 10:17:28
【问题描述】:

我需要添加一个名为 computeFrequencies 的函数,给定一个包含成绩的数组,它会返回一个包含成绩频率分布的小数组。 (这只是整个程序的一部分)

我做了这个,但是我对 c 完全陌生,我不确定我做错了什么: 给定错误: histogramtest2.c:16:10:错误:“等级”重新声明为不同类型的符号 histogramtest2.c:15:29: 注意:之前对“等级”的定义在这里 histogramtest2.c:20:12: 错误:下标值既不是数组也不是指针也不是向量

谁能帮助我? 非常感谢

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 6 7 4 8 9 2 10 4 9 5 7 4 8 6 7 2 10 4 1 8 3 6 3 6 9 4

我使用 ./a.out

输出应该是:

. . . * . * . . . .
. . . * . * . * . .
. . * * . * * * * .
. * * * . * * * * *
* * * * * * * * * *
1 2 3 4 5 6 7 8 9 10

代码:

#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;
}

【问题讨论】:

  • 问题正如错误所说:你正在重新声明已经存在的东西。
  • 数组从零开始...默认 == segfault case
  • 你可以简单地说foo(x),而不是switch(x) { case i: foo(i); /* ... */ }
  • 不确定是否有人看过编辑 =/

标签: c arrays pointers histogram


【解决方案1】:

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

首先,摆脱“幻数”常量,这些常量的含义在上下文中并不是很明显(它们通常并不是真正的常量)。例如直方图中的桶数 (10)。所以我将使用符号常量 NFREQ 来引用数字 10,它可以在包含之后使用预处理器宏 #define NFREQ 10 来定义。

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

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

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

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]++;
    }
}

不要忘记初始化频率数组。如果您使用简单的 printf 循环打印中间结果或检查调试器中的值,则很容易发现此错误。在这里,我假设成绩来自[1..10] 范围,并且成绩总数相对较低,否则您需要沿 y 轴标准化为最大值。所以这里,在简单的情况下,我们只是从grades数组中增加每个等级对应的bucket中的计数器。

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

arrayMax() 函数似乎工作正常,只要给定的长度与数组的实际长度匹配(您可以改用sentinel value)。它返回最常见等级的最高频率。

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

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");
}

最后,您可以通过调用free(grades); 显式释放以前动态分配的内存(在main 中的return 语句之前),显式释放您之前动态分配的内存。在您的情况下,这并不是一个真正的问题,因为它会在主函数返回时被隐式释放。

【讨论】:

    【解决方案2】:

    放弃重新声明:

    int i, grades[];
          ^^^^^^^^^
    

    • 旁注:在您的函数声明中int freq[10] 具有误导性 因为它相当于int freq[]
    • 第二个注意事项:如果 freq 确实有 10 个元素,freq[10] 超出范围
    • 第三个注意事项:switch 是没用的 - 你可以直接使用i 确定它在边界内

    【讨论】:

    • 嘿,我编辑了我的问题,因为即使我不再有错误,我的程序仍然无法运行,所以错误可能在其他地方,谢谢您的回答!
    猜你喜欢
    • 2015-04-26
    • 2015-10-11
    • 1970-01-01
    • 1970-01-01
    • 2022-10-14
    • 2016-08-03
    • 2020-09-11
    • 2020-08-08
    • 1970-01-01
    相关资源
    最近更新 更多