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

How to count the number of times a character symbol appears in a text file?

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

例如,如果 input.txt 包含:

Hello my name is programmer!!

然后运行:

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

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

这应该打印:

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

但是,它什么也不打印。

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

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

这是更正了 errors/warnings 的版本:

#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

需要进行许多小的更改,其中大部分已在评论中指出。这是或多或少按照我的方式修复的代码。

源代码: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;
}

示例构建和 运行

这假定存在合适的 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
$ 

注意这个程序设计是多么的不方便。每次你 运行 程序时,你都必须 运行 cat output.txt 或类似的东西才能看到产生了什么。程序优先写入标准输出而不是文件是有原因的,这说明了原因。是的,我可以使用:

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

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

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

Usage: lc symbol [input [output]]

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

Usage: lc symbol [file ...]

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

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

或:

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

有一个令人信服的论点表明强制性论点不应需要 -c 前缀。另一方面,您可以概括代码,以便如果未指定 -c symbol,它将对文件中的所有符号进行计数,并概括打印,以便打印出所有带有非字符的字符- 零计数,甚至所有计数都不管。您还可以允许 -c symbol 重复或跟踪 -c 之后字符串中的所有字符。有很多方法可以有效地改变这个程序。