我正在尝试编写一个读取文本文件的程序,然后计算符号(用户在命令行参数中的选择)在整个文本文件中出现的次数。然后它会将它出现的次数写入输出文本文件。我的问题是它没有成功打印符号或数字,而如果我计算一个LETTER出现的次数它可以正常工作。
例如,如果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);
}
答案 0 :(得分:3)
需要进行许多微小的更改,其中大多数都在评论中指出。这里的代码或多或少地按照我的方式修复。
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
之后跟踪字符串中的所有字符。有很多方法可以有效地改变这个程序。
答案 1 :(得分:2)
编译器为发布的代码提出了一些错误和一些警告。
以下是更正错误/警告的版本:
#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