【问题标题】:Printing out how many of each char from alphabet does file have. - C打印出文件中有多少个字母表中的每个字符。 - C
【发布时间】:2019-04-21 03:52:33
【问题描述】:

各位程序员大家好。我在搞清楚这个程序时遇到了很大的问题,我已经坐了几个小时了。这是我需要的。为文件中的每一行计算字符的程序。据我所知,我目前有程序计算和打印行以及打印 A-Z 字符。此外,例如 t 和 T 之间也没有区别,因此程序都算作 T。这是我编写的代码。

输入:嗨是我

输出:H - 1,I - 2,T - 1,S - 1,M - 1,E - 1

但它也会为不存在的字符打印 0。例如 A - 0 等。

int main()
{
    FILE *fr;
    char *fname, a='A',b;
    int line = 1, lines=1,i=0,counter=0,z=0;

    //Scans file name & open it

    scanf("%s",fname);
    fr = fopen(fname,"r");

    //print out first line

    printf("  ");
    for (;a<='Z';a++) {
        printf(" %c",a);
    }
    printf("\n");

    //calculate how many lines file has

    while (fscanf(fr,"%c",&b) != EOF) {
        if (b == '\n') {
            lines++;
        }
    }

    //cycle for printing lines

    for (;line<=lines;) {
        printf("%d  ",line);

        //check till end of file

        while ((fscanf(fr,"%c",&b) != EOF)) {
            printf("%c ",a);
            //check a-z
            for (a='A';a<='Z';a++) {
                if (b == a || a+32 == b) {
                    counter++;
                }
                else if (b == '\n') {
                    line++; printf("\n");
                }

            }
            printf("%d ",counter);
            counter=0;
        }
    }
    fclose(fr);
    return 0;
}

【问题讨论】:

  • 它会打印,因为您要求它。将这些打印语句移动到测试counterif
  • 但是我会收到例如 A 是否在文件中两次 A - 1 1 而不是 A - 2
  • 因为您正在立即打印结果。现在,如果只有某种方法可以将它们存储到某种列表中......
  • 我确实尝试过使用数组,这很痛苦,因为我不知道如何告诉它它是新行,所以它应该停止并打印当前行的结果,然后开始计算另一行
  • 您忘记倒带文件了。

标签: c file char


【解决方案1】:

建议:

消除任何“神奇”数字:

#define MAX_FILENAME_LEN 100
#define MAX_LINE_LEN     1024
#define MAX_CHARACTERS   256

替换:

char *fname, a='A',b;

与:

char fname[ MAX_FILENAME_LEN ];

否则,尝试将文件名读入一些随机内存(导致段错误事件的好方法,它是未定义的行为)

替换:

printf("  ");
for (;a<='Z';a++) {
    printf(" %c",a);
}
printf("\n");

与:

char line[ MAX_LINE_LEN ];
fgets( line, sizeof line, fr );
printf( "%s", line );

替换这个:

scanf("%s",fname);
fr = fopen(fname,"r");

与:

if( scanf("%99s",fname) != 1 )
{
    fprintf( stderr, "scanf failed to input file name"
    exit( EXIT_FAILURE );
}
// implied else, scanf successful

fr = fopen(fname,"r");
if( !fr )
{
    perror( "fopen failed" );
    exit( EXIT_FAILURE );
}
// implied else, fopen successful

替换

    while (fscanf(fr,"%c",&b) != EOF) {
    if (b == '\n') {
        lines++;
    }
}

与:

int lines = 1;
while( fgets( line, sizeof line, fr ) )
{
    lines++;
}
rewind( fr );

替换:

        while ((fscanf(fr,"%c",&b) != EOF)) {
        printf("%c ",a);
        //check a-z
        for (a='A';a<='Z';a++) {
            if (b == a || a+32 == b) {
                counter++;
            }
            else if (b == '\n') {
                line++; printf("\n");
            }

        }
        printf("%d ",counter);
        counter=0;
    }

与:

int counts[ MAX_CHARACTERS ];
...
// use `While()` loop with `fgets()` to read data into `line[]`
...
memset( counts, '\0', sizeof( counts ) ); 

for( int i=0; line[i]; i++ )
{
    counts[ line[i] ]++; 
}

for( int i=0; i<MAX_CHARACTERS; i++) 
{ 
    if( counts[i] ) 
    {
        printf( "%c - %i\n" , (char)i, counts[ i ] ); 
    } 
}

您可能想要“调整”上述内容,使其不输出标点符号、换行符等。

您可能需要“调整”以上内容以将大小写字母字符计为相同。一个简单的方法是

#include <ctype.h>

然后对于从 'line[]' 数组中选择的每个字符:

line[i] = tolower( line[i] ); 

注意:exit()EXIT_FAILURE在头文件中找到:stdlib.h

【讨论】:

  • 任何原因,特别是您不想将所有操作组合在一个 while( fgets( line, sizeof line, fr ) 循环下并避免从文件中多次读取并需要 rewind()?
  • @DavidC.Rankin,我遵循了 OP 的代码逻辑,否则,我可以很容易地将我的答案写成一个循环,但是,OP 发布的代码会输出输入中的行数文件,在处理输入文件中的任何行之前,因此需要先计算输入文件中的行数(遵循 OPs 代码逻辑),然后回到文件开头并处理每个行
  • 我想的也差不多。你的建议很好,但解释有点有限。 (用...替换...)有时给 OP 一些(为什么...)和概述如何整理事情并不是一个坏主意。在这里,如果他们使用一个简短的示例文件,那真的没关系,但是如果文件很大,那么阅读一次就会获得很大的效率。
猜你喜欢
  • 2017-08-10
  • 1970-01-01
  • 2020-03-29
  • 1970-01-01
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多