如何计算字符符号在文本文件中出现的次数?

时间:2022-01-22 19:34:47

I am trying to write a program that reads in a text file and then counts the number of times a symbol (user's choice from the command line argument) appears throughout the text file. It then writes the number of times it appears to an output text file. My problem is that it doesn't successfully print symbols or numbers, whereas if I count the number of times a LETTER appears it works fine.

我正在尝试编写一个读取文本文件的程序,然后计算符号(用户从命令行参数中选择)在整个文本文件中出现的次数。然后它会将它出现的次数写入输出文本文件。我的问题是它没有成功打印符号或数字,而如果我计算一个LETTER出现的次数它工作正常。

For example, if input.txt contains:

例如,如果input.txt包含:

Hello my name is programmer!!

Then running:

$ gcc myProgram.c
$ ./a.out input.txt output.txt !

Note First argument: input.txt , Second argument: output.txt , Third argument: !

注意第一个参数:input.txt,第二个参数:output.txt,第三个参数:!

This should print:

这应该打印:

$ cat output.txt
The character being written was '!' and it occurred 2 times.
$

However, it prints nothing.

但是,它什么都不打印。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(int argc, char *argv[]){

    FILE *finp;
    FILE *output;
    char letter;

    int ex=0;

    if((finp=fopen(argv[1], "r")) == NULL){

        printf("Error Reading input!\n");

    }

    while((letter = fgetc(finp))!=EOF){

        /*From ASCII TABLE*/
        if(letter==33){
            ex++;}}

    if(output=fopen(argv[2], "w")){


        if(strcmp(argv[3],"!")==0){
            fprintf(output, "The character being written was '%s' and it occured %d
                    times", argv[3], ex);
        }


        if(output==NULL){
            printf("ERROR\n");
            exit(1);
        }

    }
    fclose(finp);
}

2 个解决方案

#1


2  

There were several errors and some warnings raised by the compiler for the posted code.

编译器为发布的代码提出了一些错误和一些警告。

Here is a version with the errors/warnings corrected:

这是一个错误/警告更正的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *finp   = NULL;
    FILE *output = NULL;
    int   letter; // character to be found

    int ex=0; // character occurrence counter

    if( 4 != argc )
    { // then wrong number of parameters.
        printf( "usage: %s <inFileName> <outFileName> <searchChar>", argv[0] );
        exit( EXIT_FAILURE );
    }

    // implied else, right number of parameters

    if( NULL == (finp=fopen(argv[1], "r") ) )
    {
        perror( "fopen for the input file failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    if( NULL == (output=fopen(argv[2], "w") ) )
    {
        perror( "fopen for the output file failed" );
        fclose( finp ); // cleanup
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    while( EOF != (letter = fgetc(finp) ) )
    {
        /*From ASCII TABLE*/
        if( letter == argv[3][0] )
        { // then desired character found
            ex++;
        } // end if
    } // end while

    fprintf(
        output,
        "The search character is '%c' and it occurred %d times\n",
        argv[3][0],
        ex);

    fclose(finp);
    fclose(output);
    return 0;
} // end function: main

#2


3  

There are numerous little changes required, most of them identified in the comments. Here's the code fixed more or less the way I'd do it.

需要进行许多微小的更改,其中大多数都在评论中指出。这里的代码或多或少地按照我的方式修复。

Source code: lc.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *finp;
    FILE *output;
    int symbol;
    int letter;
    int count = 0;

    if (argc != 4)
    {
        fprintf(stderr, "Usage: %s input output symbol\n", argv[0]);
        exit(1);
    }

    if ((finp = fopen(argv[1], "r")) == NULL)
    {
        fprintf(stderr, "Error opening file %s for input\n", argv[1]);
        exit(1);
    }

    if ((output = fopen(argv[2], "w")) == NULL)
    {
        fprintf(stderr, "Error opening file %s for output\n", argv[2]);
        exit(1);
    }

    symbol = argv[3][0];

    while ((letter = fgetc(finp)) != EOF)
    {
        if (letter == symbol)
            count++;
    }

    fprintf(output, "The character being written was '%c' and it occurred %d times\n",
            symbol, count);

    fclose(finp);
    fclose(output);
    return 0;
}

Sample build and run

This assumes a suitable makefile exists to give you the compilation flags shown. It's a subset of the flags I actually use, but the extra flags don't yield any extra warnings (errors) on this code.

这假定存在一个合适的makefile来为您提供显示的编译标志。它是我实际使用的标志的子集,但额外的标志不会在此代码上产生任何额外的警告(错误)。

$ make lc
    gcc -O3 -g -std=c11 -Wall -Wextra -Werror lc.c -o lc 
$ cat input.txt
Hello my name is programmer!!
$ ./lc input.txt output.txt !
$ cat output.txt
The character being written was '!' and it occurred 2 times
$ ./lc input.txt output.txt e
$ cat output.txt
The character being written was 'e' and it occurred 3 times
$ ./lc input.txt output.txt m
$ cat output.txt
The character being written was 'm' and it occurred 4 times
$ ./lc input.txt output.txt Z
$ cat output.txt
The character being written was 'Z' and it occurred 0 times
$ 

Note how inconvenient this program design is. Each time you run the program, you have to run cat output.txt or something similar to see what was produced. There's a reason why programs write to standard output in preference to files, and this illustrates why. Yes, I could use:

请注意这个程序设计有多么不方便。每次运行程序时,都必须运行cat output.txt或类似的东西来查看生成的内容。程序写入标准输出优先于文件是有原因的,这就说明了原因。是的,我可以使用:

$ ./lc input.txt /dev/stdout o
The character being written was 'o' and it occurred 2 times
$ 

but it would be more convenient not to need to do so.

但是不需要这样做会更方便。

Since the symbol to be counted is pretty much mandatory, it should be the first argument. The second argument should be optional but could specify the input file; if it is not supplied, the program would read standard input. The third argument could also be optional, specifying the output file, defaulting to standard output:

由于要计数的符号几乎是强制性的,因此它应该是第一个参数。第二个参数应该是可选的,但可以指定输入文件;如果没有提供,程序将读取标准输入。第三个参数也可以是可选的,指定输出文件,默认为标准输出:

Usage: lc symbol [input [output]]

Alternatively, and probably both more usefully and more conventionally, it should always write to standard output, and should read all the files on the command line after the mandatory symbol argument:

或者,可能更有用也更常规,它应始终写入标准输出,并应在强制符号参数后读取命令行上的所有文件:

Usage: lc symbol [file ...]

If you want the output to go to a file, use I/O redirection. Or allow the output to be specified via an option and argument:

如果要将输出转到文件,请使用I / O重定向。或者允许通过选项和参数指定输出:

Usage: lc [-o output] symbol [file ...]

or:

Usage: lc [-o output] -c symbol [file ...]

There's a cogent argument for suggesting that a mandatory argument should not need the -c prefix. On the other hand, you could generalize the code so that if the -c symbol was not specified, it would do a count of all the symbols in the file, and generalize the printing so it printed out all the characters with a non-zero count, or even all the counts regardless. You might also allow -c symbol to repeat, or track all the characters in the string after the -c. There are many ways to vary this program usefully.

有一个有说服力的论据,建议强制参数不需要-c前缀。另一方面,你可以推广代码,这样如果没有指定-c符号,它将对文件中的所有符号进行计数,并对打印进行概括,以便打印出所有非零的字符。计算,甚至所有计数。您可能还允许-c符号重复,或跟踪-c后字符串中的所有字符。有许多方法可以有效地改变这个程序。

#1


2  

There were several errors and some warnings raised by the compiler for the posted code.

编译器为发布的代码提出了一些错误和一些警告。

Here is a version with the errors/warnings corrected:

这是一个错误/警告更正的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *finp   = NULL;
    FILE *output = NULL;
    int   letter; // character to be found

    int ex=0; // character occurrence counter

    if( 4 != argc )
    { // then wrong number of parameters.
        printf( "usage: %s <inFileName> <outFileName> <searchChar>", argv[0] );
        exit( EXIT_FAILURE );
    }

    // implied else, right number of parameters

    if( NULL == (finp=fopen(argv[1], "r") ) )
    {
        perror( "fopen for the input file failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    if( NULL == (output=fopen(argv[2], "w") ) )
    {
        perror( "fopen for the output file failed" );
        fclose( finp ); // cleanup
        exit( EXIT_FAILURE );
    }

    // implied else, fopen successful

    while( EOF != (letter = fgetc(finp) ) )
    {
        /*From ASCII TABLE*/
        if( letter == argv[3][0] )
        { // then desired character found
            ex++;
        } // end if
    } // end while

    fprintf(
        output,
        "The search character is '%c' and it occurred %d times\n",
        argv[3][0],
        ex);

    fclose(finp);
    fclose(output);
    return 0;
} // end function: main

#2


3  

There are numerous little changes required, most of them identified in the comments. Here's the code fixed more or less the way I'd do it.

需要进行许多微小的更改,其中大多数都在评论中指出。这里的代码或多或少地按照我的方式修复。

Source code: lc.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *finp;
    FILE *output;
    int symbol;
    int letter;
    int count = 0;

    if (argc != 4)
    {
        fprintf(stderr, "Usage: %s input output symbol\n", argv[0]);
        exit(1);
    }

    if ((finp = fopen(argv[1], "r")) == NULL)
    {
        fprintf(stderr, "Error opening file %s for input\n", argv[1]);
        exit(1);
    }

    if ((output = fopen(argv[2], "w")) == NULL)
    {
        fprintf(stderr, "Error opening file %s for output\n", argv[2]);
        exit(1);
    }

    symbol = argv[3][0];

    while ((letter = fgetc(finp)) != EOF)
    {
        if (letter == symbol)
            count++;
    }

    fprintf(output, "The character being written was '%c' and it occurred %d times\n",
            symbol, count);

    fclose(finp);
    fclose(output);
    return 0;
}

Sample build and run

This assumes a suitable makefile exists to give you the compilation flags shown. It's a subset of the flags I actually use, but the extra flags don't yield any extra warnings (errors) on this code.

这假定存在一个合适的makefile来为您提供显示的编译标志。它是我实际使用的标志的子集,但额外的标志不会在此代码上产生任何额外的警告(错误)。

$ make lc
    gcc -O3 -g -std=c11 -Wall -Wextra -Werror lc.c -o lc 
$ cat input.txt
Hello my name is programmer!!
$ ./lc input.txt output.txt !
$ cat output.txt
The character being written was '!' and it occurred 2 times
$ ./lc input.txt output.txt e
$ cat output.txt
The character being written was 'e' and it occurred 3 times
$ ./lc input.txt output.txt m
$ cat output.txt
The character being written was 'm' and it occurred 4 times
$ ./lc input.txt output.txt Z
$ cat output.txt
The character being written was 'Z' and it occurred 0 times
$ 

Note how inconvenient this program design is. Each time you run the program, you have to run cat output.txt or something similar to see what was produced. There's a reason why programs write to standard output in preference to files, and this illustrates why. Yes, I could use:

请注意这个程序设计有多么不方便。每次运行程序时,都必须运行cat output.txt或类似的东西来查看生成的内容。程序写入标准输出优先于文件是有原因的,这就说明了原因。是的,我可以使用:

$ ./lc input.txt /dev/stdout o
The character being written was 'o' and it occurred 2 times
$ 

but it would be more convenient not to need to do so.

但是不需要这样做会更方便。

Since the symbol to be counted is pretty much mandatory, it should be the first argument. The second argument should be optional but could specify the input file; if it is not supplied, the program would read standard input. The third argument could also be optional, specifying the output file, defaulting to standard output:

由于要计数的符号几乎是强制性的,因此它应该是第一个参数。第二个参数应该是可选的,但可以指定输入文件;如果没有提供,程序将读取标准输入。第三个参数也可以是可选的,指定输出文件,默认为标准输出:

Usage: lc symbol [input [output]]

Alternatively, and probably both more usefully and more conventionally, it should always write to standard output, and should read all the files on the command line after the mandatory symbol argument:

或者,可能更有用也更常规,它应始终写入标准输出,并应在强制符号参数后读取命令行上的所有文件:

Usage: lc symbol [file ...]

If you want the output to go to a file, use I/O redirection. Or allow the output to be specified via an option and argument:

如果要将输出转到文件,请使用I / O重定向。或者允许通过选项和参数指定输出:

Usage: lc [-o output] symbol [file ...]

or:

Usage: lc [-o output] -c symbol [file ...]

There's a cogent argument for suggesting that a mandatory argument should not need the -c prefix. On the other hand, you could generalize the code so that if the -c symbol was not specified, it would do a count of all the symbols in the file, and generalize the printing so it printed out all the characters with a non-zero count, or even all the counts regardless. You might also allow -c symbol to repeat, or track all the characters in the string after the -c. There are many ways to vary this program usefully.

有一个有说服力的论据,建议强制参数不需要-c前缀。另一方面,你可以推广代码,这样如果没有指定-c符号,它将对文件中的所有符号进行计数,并对打印进行概括,以便打印出所有非零的字符。计算,甚至所有计数。您可能还允许-c符号重复,或跟踪-c后字符串中的所有字符。有许多方法可以有效地改变这个程序。