首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用ASCII-art图计算字母程序

用ASCII-art图计算字母程序
EN

Code Review用户
提问于 2012-11-26 11:00:16
回答 1查看 274关注 0票数 5

我正在用C语言编写一个在UNIX上运行的程序,它计算输入文本文件中每个字母的数量。对于这样的文件:

猫坐在绿色的垫子上

输出如下:

代码语言:javascript
复制
   The letter ’a’ occurs 3 times.
   The letter ’c’ occurs 1 times.
   The letter ’e’ occurs 4 times.
   The letter ’g’ occurs 1 times.
   The letter ’h’ occurs 2 times.
   The letter ’m’ occurs 1 times.
   The letter ’n’ occurs 2 times.
   The letter ’o’ occurs 1 times.
   The letter ’r’ occurs 1 times.
   The letter ’s’ occurs 1 times.
   The letter ’t’ occurs 5 times.

  5                    *
  4     *              *
  4     *              *
  3 *   *              *
  3 *   *              *
  2 *   *  *     *     *
  2 *   *  *     *     *
  1 * * * **    ***  ***
  1 * * * **    ***  ***
  0 **************************
  0 **************************
... abcdefghijklmnopqrstuvwxyz

其中,图表表示字母出现的次数。(如果大于10,我只需在第10行后加上'+‘)。我目前编写的实现这一目标的代码如下:(还没有找到一种测试大写字母和小写字母的好方法)。

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

void drawGraph(int letters[26], char alpha[26]);
void printLetters(int letters[26], char alpha[26]);
void getLetters(FILE *fp, int letters[26], char alpha[26]);

int main(int argc, char *argv[]) {
  FILE *fp;
  int letters[26] = { 0 };
  char alpha[26] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };
  int indexedAlpha[256] = { 0 };
  int j = 1;

  for (i = 97; i <= 127; i++)
    {
      indexedAlpha[i] = j;
      j++;
    }

  //open file
  if ((fp = fopen(argv[1], "r")) == NULL)
    {
      perror("Cannot open file");
      exit(EXIT_FAILURE);
    }

  getLetters(fp, letters, alpha);
  printLetters(letters, alpha);
  printf("\n");
  drawGraph(letters, alpha);
  printf("\n");

  return EXIT_SUCCESS;
}

void getLetters(FILE *fp, int letters[26], char alpha[26]) {
  int c;
  for (int i = 0; (c = fgetc(fp)) != EOF; i++)
    {
      c = fgetc(fp);
      if ( isalpha(c) )
    {
      for ( int j = 0; j < 26; j++ ) //find which letter it is
        {
          if( c == alpha[j] ) 
        {
          letters[j]++;
          break;
        }
        }
    }
    }
}

void printLetters(int letters[26], char alpha[26]) {
  for( int i = 0; i < 26; i++ )
    {
      if(letters[i] != 0){
    printf("The letter '%c' occurs %d times.\n", alpha[i], letters[i]);
      }
    }
}

void drawGraph(int letters[26], char alpha[26]) {
  int x = 11;
  int y;
  while(x >= 0)
    { 
      y = 0;
      while (y < 2)
    {
      if (x == 10)
        {
          printf(" %d ", x);
        }
      else if (x == 11)
        {
          printf("    ");
        }
      else
        {
          printf("  %d ", x);
        }

      for( int i = 0; i < 26; i++ )
        {
          if(letters[i] > 10)
        {
          printf("+");
          letters[i] = 10;
          y++; // Break out of while loop
        }
          else if(letters[i] == x)
        {
          printf("*");
        }
          else
        {
          printf(" ");
        }
          if (letters[i] == x && y == 1)
        {
          letters[i] = letters[i] - 1;
        }
        }
      printf("\n");
      y++;
    }
      x--;
    }
  printf("... ");

  for( int i = 0; i < 26; i++ )
    {
      printf("%c", alpha[i]);
    }
}

我要找的是关于表示法、效率(编写的代码数量和内存使用量)以及任何其他好的提示/最佳实践或更好的方法来完成这项任务的建议和技巧。

谢谢!

EN

回答 1

Code Review用户

回答已采纳

发布于 2012-11-26 16:26:50

当我第一次读到这个问题的时候,我对这个图表印象深刻。

9~10成熟。

读取文件时的小错误:

代码语言:javascript
复制
char c;
for (int i = 0; !feof(fp); i++)
{
    c = fgetc(fp);

这在所有语言中都是错误的。除非你读过eof,否则就不会设置eof。最后一篇成功的读物是读到(但不是过去)的。因此,即使文件中没有其他字符,也不会设置eof标志(直到您尝试在eof之后读取该字符)。

因此,你正在遭受一个一次性的错误。该循环对多个执行一次。最后一次迭代中'c‘的值被截断成一个字符。

因此,标准的模式是从文件中读取并查看它是否有效。如果它有效,那么进入循环:

代码语言:javascript
复制
int c;
for (int i = 0; (c = fgetc(fp)) != EOF; i++)
{

注意,我们需要将c从一个char更改为一个int,以确保EOF不会从值中被截断。

不是一个错误:但是您正在实现O(1)操作是O(n)。

代码语言:javascript
复制
  for ( int j = 0; j < 26; j++ ) //find which letter it is
    {
      if( c == alpha[j] ) 
    {
      letters[j]++;
      break;
    }

尽管你可以倒置数组,但是你可以稍微多一点。所以你用这封信来查找它的ID。

代码语言:javascript
复制
char alpha[256] = 
{  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   //  0->15 ignore
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 16->31 ignore      
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 32->47 ignore      
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 48->63 ignore      
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 64->79 ignore      
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 80->95 ignore      
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,   // 96->111 a -     
   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, 0,   // 112->127 -z     
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   // 128->143 ignore  

   .. etc

   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};  // 240->255 ignore      

   // Now the lookup becomes:
   if (alpha[c] != 0) 
   {
       letters[alpha[c] - 1]++;
   }

但你真的在乎你是否算上了所有的角色。我不会(除非有一些严重的空间限制)。你可以数数所有的字符。当你把它们打印出来时,你只需打印出你想要的。

代码语言:javascript
复制
   int letters[256];

   ....
   letters[c]++;   // or maybe letters[tolower(c)]++;
   .....

   // Now we just need to de reference the count of the letters we are interested in.
   for( int i = 0; i < 26; i++ )
   {
       int count = letters[alpha[i]];
       if(count != 0){
           printf("The letter '%c' occurs %d times.\n", alpha[i], count);
       }
   }

一些小的整理(你似乎有嵌入标签,混乱的间隔在这个网站)。

票数 7
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/19019

复制
相关文章

相似问题

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