【问题标题】:Counting Character usage in text file? C计算文本文件中的字符使用情况? C
【发布时间】:2017-10-19 17:16:16
【问题描述】:

嗨,
我需要计算一些纯文本文件中字母字符的使用情况。这就是我带来的。基本上只是运行文本文件并将每个字符与特定搜索字符的 ASCII 值进行比较。
当我运行它时,我能看到的只是第一个 printf() 字符串,并且当我关闭控制台时只是终止状态的错误。
我确实在与 .exe 文件相同的文件夹中有一个 text.txt 文件,但我什么都看不到。

不确定我的语法是否不好,甚至语义不好。
谢谢帮助! :-)

#include <stdio.h>
#include <stdlib.h>
#define ASCIIstart 65 
#define ASCIIend 90

void main(){
    FILE *fopen(), *fp;
    int c;
    unsigned int sum;

    fp = fopen("text.txt","r");

    printf("Characters found in text: \n");

    for (int i = ASCIIstart; i <= ASCIIend; i++){
        sum = 0;
        c = toupper(getc(fp));
        while (c != EOF){
            if (c == i){
                sum = sum++;
            }
            c = toupper(getc(fp));
        }
        if (sum > 0){
            printf("%c: %u\n",i,sum);
        }
    }
    fclose(fp);
}

【问题讨论】:

  • 如果您使用库函数isalpha,您将不必担心硬编码幻数或大小写。你需要#include &lt;ctype.h&gt;
  • 你为什么要sum = sum++;?你不觉得sum++ 就够了吗?
  • 你在说什么神奇的数字?抱歉,我是 C 编程的小菜鸟:/ - 这是学校的习惯,我们必须在 Pascal 中使用它
  • 你为什么要声明 fopen() ?
  • 你不认为你的 for 循环应该在 while 循环内部而不是在外部吗?

标签: c character text-files counter toupper


【解决方案1】:

您可以这样做,而不是为每个字符查找整个文件

FILE *fp;
int c, sum[ASCIIend - ASCIIstart + 1]={0};
fp = fopen("file.txt,"r");
if(fp==NULL)
{
    perror("Error");
    return 1;
}

int i;
while( (c = toupper(getc(fp)))!= EOF)
{
    if(c>=ASCIIstart && c<=ASCIIend)
    {
        sum[c-ASCIIstart]++;
    }
}
for(i=ASCIIstart; i<=ASCIIend; ++i)
{
    printf("\n%c: %d", i, sum[i-ASCIIstart]);
}

您必须检查fopen()的返回值,以确保文件已成功打开。

有一个数组sum 保存了ASCIIendASCIIstart 宏表示的范围内每个字符的出现次数。

数组的大小就是要统计出现次数的字符数。

使用sum[c-ASCIIstart] 是因为cASCIIstart 的ASCII 值(如果编码确实是ASCII)之间的差异会给出与c 关联的索引。

我不知道FILE *fopen(), fp; 是什么意思,但fopen() 是C 中用于打开文件的函数的名称。

FILE *fopen(), *fp;

你给出了函数fopen()的原型。

但是在stdio.h,已经有fopen()的原型了

FILE *fopen(const char *path, const char *mode);

但没有显示任何错误(如果有),因为fopen() 表示该函数可以有任意数量的参数。看看here

如果您的FILE *fopen(); 的返回类型不是FILE *,或者如果它显示为int 等其他参数类型,您肯定会遇到错误。

而且,void main() 不被认为是好的做法。请改用int main()。看here

【讨论】:

    【解决方案2】:

    您可以使用字符数组,一次遍历解析文件内容,最后显示数组计数。

    #include <stdio.h>
    #include<ctype.h>
    
    void main(){
    FILE *fopen(), *fp;
    int c;
    fp = fopen("test.txt","r");
    printf("Characters found in text: \n");
    char charArr[26]= {0};
    c = toupper(fgetc(fp));
    
    while(c!=EOF) {
      charArr[c-'A']=charArr[c-'A']+1;
      c = toupper(fgetc(fp));
    }
    fclose(fp);
    for(int i=0;i<26;i++){
       printf("\nChar: %c | Count= %d ",i+65,charArr[i]);
    }
    }
    

    希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      因为第一次之后你是文件的结尾。 你的 c = toupper(getc(fp));之后返回 -1。

      【讨论】:

      • 哦,我明白了.. 那么我应该使用...while ((c = getc(fp)) != EOF)... 并添加一个 if 语句吗?
      【解决方案4】:

      为了只计算一个字符,您正在阅读整个文件并为每个字符重复此操作。相反,您可以这样做:

      #include <stdio.h>
      #include <stdlib.h>
      #include <ctype.h>
      
      #define ASCIIstart 65 
      #define ASCIIend 90
      
      int main(){
          FILE  *fp;
          int c, i;
          int alphabets[26] = {0};
      
          fp = fopen("text.txt","r");
          if (fp == NULL){
              fprintf (stderr, "Failed to open file\n");
              return -1;
          }
      
          while ((c = toupper(fgetc(fp))) != EOF){
              if (c >= ASCIIstart && c <= ASCIIend)
                  alphabets[c - ASCIIstart]++;
          }
      
          fclose(fp);
          fprintf(stdout, "Characters found in text: \n");
          for (i = 0; i < 26; i++)
              fprintf (stdout, "%c: %d\n", i+ASCIIstart, alphabets[i]);
          return 0;
      }
      

      【讨论】:

        【解决方案5】:

        TLDR

        使用您的代码,您的循环是由内而外的。

        我将用伪代码回答以保持概念简单明了。

        现在你正在这样做:

         FOR LETTER = 'A' TO 'Z': 
              WHILE FILE HAS CHARACTERS
                   GET NEXT CHARACTER
                   IF CHARACTER == LETTER 
                        ADD TO COUNT FOR CHAR
                   END IF
              END WHILE
         END FOR
        

        问题是您正在运行带有字符“A”的文件,然后到达文件末尾,因此对于“B”没有任何操作...“Z”

        如果你交换了这个:

         WHILE FILE HAS CHARACTERS
              GET NEXT CHARACTER 
                  FOR LETTER = 'A' TO 'Z'
                      IF LETTER = UCASE(CHARACTER)
                           ADD TO COUNT FOR LETTER
                      END IF
                  END FOR
         END WHILE
        

        显然对每个字母进行 26 次检查太多了,所以也许是更好的方法。

         LET COUNTS = ARRAY(26) 
        
         WHILE FILE HAS CHARACTERS
                 CHARACTER := UCASE(CHARACTER)
                 IF CHARACTER >= 'A' AND CHARACTER <= 'Z'
                    LET INDEX = CHARACTER - 'A'
                    COUNTS[INDEX]++
                 ENDIF
         END WHILE
        

        您可以将伪代码翻译成 C 作为练习。

        【讨论】:

          【解决方案6】:

          在 for 循环结束时将指针倒回到文件的开头?

          这个已经发过:Resetting pointer to the start of file

          附: - 可以为你的输出值使用一个数组:int charactercount[pow(2,sizeof(char))] 这样你就不必重复解析文件了?

          编辑:缺少 pow()

          【讨论】:

          • 仍然无法正常工作,我通过在每个 for 循环的末尾添加它来更改 ti... fseek(fp,0,SEEK_SET) 但除了第一个 printf 之外什么都没有。我这样做的方式,没有数组,有问题吗?它会导致一些问题吗?
          • 它将使您的执行时间为 o(n^2) 而不是 o(n)。另外,如果你使用数组,你只需要通过一次。
          猜你喜欢
          • 1970-01-01
          • 2015-01-29
          • 2013-06-25
          • 1970-01-01
          • 2020-01-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-05
          相关资源
          最近更新 更多