我一直在编写一个程序,将数据写入文本文件,并在c中练习数据处理,然后从中找到数据,每个数据都存储为行。有行,数据逐行存储,例如:
学生姓名 学生姓氏学生电话等
当我输入"0"时;学生姓名";它开始打印而不打印姓名本身,打印后面的内容,如果我搜索姓氏,也会发生同样的情况,只会打印出手机。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
FILE *filePtr;
filePtr=fopen("std.txt","r");
char char_input[50];
char string[500];
printf("%s","Please give an input of the phone numbern");
scanf("%s",char_input);
while(!feof(filePtr)){
fscanf(filePtr,"%s",string);
if(strcmp(string, char_input)== 0){
fgets(string,500,filePtr);
puts(string);
}
}
fclose(filePtr);
}
文本文件:
Andrew Brooks 865 965 55
输入:
Andrew
输出:
Brooks 865 965 55
期望输出:
Andrew Brooks 865 965 55
而不是错误地使用feof()
和fscanf(filePtr,"%s", ...
来错误地读取行。使用fgets()
读取文件的行并转换为字符串。
-
测试
fgets()
的返回值以查看是否发生了输入。 -
使用
strstr()
在string
中查找匹配的子字符串。
示例:
while (fgets(string, sizeof string, filePtr)) {
if (strstr(string, char_input)){
fputs(string, stdout);
}
}
函数feof
只会告诉您以前的输入操作是否已经遇到文件末尾。它不会告诉您现在是否已到达文件末尾,因此下一次输入操作将失败。该功能无法预测对fscanf
或fgets
的下一次输入操作是否会失败。因此,通常不应将其用作循环条件。请参阅此问题以获取更多信息:为什么"while(!feof(file))"总是错误的?
在您的情况下,feof
可能返回false,并且由于遇到文件末尾,对fscanf
的后续函数调用可能返回EOF
。在这种情况下,您发布的代码将忽略fscanf
的返回值,并表现为fscanf
已经成功,并且您发布的编码将尝试处理不存在的输入。这可能会导致一个错误。
因此,您不应该使用函数feof
来确定是否应该继续循环,而应该检查输入函数的返回值。
你可以这样重写你的循环:
while ( fscanf(filePtr,"%s",string) == 1 ) {
if ( strcmp(string, char_input ) == 0 ) {
fgets( string, 500, filePtr );
puts( string );
}
}
这将解决上述不检查CCD_ 16的返回值的问题。然而,根据确切的输入,函数fgets
也可能因遇到文件末尾而失败。因此,最好您的程序也检查函数fgets
的返回值,而不是简单地假设函数成功。
另一个问题是线路
puts(string);
将只打印string
的内容,即" Brooks 865 965 55"
。但是,您还想打印"Andrew"
,它被fscanf
函数调用读取,但同时被fgets
函数调用覆盖。最简单的解决方案是在它被覆盖之前将其打印出来。然而,如果用户搜索"Brooks"
而不是"Andrew"
,这将不起作用,因为单词"Andrew"
将在先前循环迭代中已经被丢弃。这是因为在循环中调用fscanf(filePtr,"%s",string)
不会在每次循环迭代中读取一行输入,而是在每次循环循环迭代中只读取一个字(这不是很有意义)。
使用fscanf(filePtr,"%s",string)
逐字逐句读取输入文件的另一个后果是,您将无法找到与电话号码"865 965 55"
匹配的号码。这是因为您的程序将首先从输入文件读取CCD_;单词";与搜索字符串不相同。然后它将读取"965"
并确定相同的事情。它对"55"
也是如此。
最好的解决方案可能是重新设计循环,使其在每次循环迭代中始终只读取一行输入,而不是每次循环迭代仅读取一个单词。在读取一行输入后,您可以通过将该行拆分为"来解析该行;名字"姓氏";以及";电话号码";使用函数CCD_ 33。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *filePtr;
char search_string[50];
char line[200];
//open input file
filePtr = fopen( "std.txt", "r" );
if ( filePtr == NULL )
{
fprintf( stderr, "unable to open input file!n" );
exit( EXIT_FAILURE );
}
//prompt user for input
printf( "Please enter search string: " );
//Note that the following code now uses "fgets" instead
//of "fscanf", because fscanf will only read a single
//word, when using the "%s" format specifier. This means
//that it would be unable to read the phone number
//"865 965 55" as an input string, because that line
//consists of three "words".
//read exactly one line of input from user
if ( fgets( search_string, sizeof search_string, stdin ) == NULL )
{
fprintf( stderr, "input failure!n" );
exit( EXIT_FAILURE );
}
//remove newline character from input line by
//replacing it with terminating null character
search_string[strcspn(search_string,"n")] = ' ';
//read exactly one line of input from the input file
//per loop iteration
while ( fgets( line, sizeof line, filePtr ) != NULL )
{
char first_name[50];
char last_name[50];
char phone_number[50];
//attempt to parse input
if (
sscanf(
line,
"%49s %49s %49[^n]",
first_name,
last_name,
phone_number
)
!= 3
)
{
fprintf(
stderr,
"WARNING: skipping line due to parse error!n"
);
continue;
}
//parsing was successful, so we can now search the
//3 individual fields for the search string
if (
strcmp( search_string, first_name ) == 0
||
strcmp( search_string, last_name ) == 0
||
strcmp( search_string, phone_number ) == 0
)
{
//remove newline character from input line by
//replacing it with terminating null character
line[strcspn(line,"n")] = ' ';
//print entire input line of file for user
printf( "%sn", line );
}
}
//cleanup
fclose(filePtr);
}
该程序具有以下行为:
Please enter search string: Andrew
Andrew Brooks 865 965 55
Please enter search string: Brooks
Andrew Brooks 865 965 55
Please enter search string: 865 965 55
Andrew Brooks 865 965 55
请注意,上面的代码并不完美,因为它有以下问题:
- 使用
fgets
时,如果输入行太长,无法放入缓冲区,则程序将不会检测到这一点,尽管在这种情况下,它可能会打印错误消息并退出 - 如果任何字段";名字"姓氏";或";电话号码";大于49个字符,代码确实防止了缓冲区溢出(这可能会导致程序崩溃),但它仍然不能正确处理这种情况,例如通过检查这种情况和打印适当的错误消息
但是,出于您的目的,代码可能已经足够了。
解决这些问题的一个更强大的程序是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//This function will read exactly one line of input using
//fgets and verify that the line was not too long for the
//input buffer. Note that the buffer size must be two bytes
//longer than the actual string length, because there must
//be space for the newline character and the terminating
//null character. The newline character will be overwritten
//with another terminating null character.
//On success, it will return true. If not further input is
//available due to end-of-file, it will return false.
//Otherwise, the function will not return, but will
//terminate the program with an error message.
bool get_one_line_of_user_input( char *buffer, int buffer_size )
{
char *p;
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
if ( feof( stdin ) )
{
return false;
}
else
{
fprintf( stderr, "input error!n" );
exit( EXIT_FAILURE );
}
}
p = strchr( buffer, 'n' );
if ( p == NULL )
{
//No newline character was found. This could mean
//that the line was too long to store in the input
//buffer, in which case, the program should quit
//with an error message. However, it could also mean
//that input has been redirected to come from a
//file, and that this file ends with a line without
//a line ending. In that case, the missing newline
//character can be ignored.
if ( !feof( stdin ) )
{
fprintf( stderr, "line too long for buffer!n" );
exit( EXIT_FAILURE );
}
}
else
{
//remove newline character
*p = ' ';
}
return true;
}
int main()
{
FILE *filePtr;
char search_string[50];
char line[200];
//open input file
filePtr = fopen( "std.txt", "r" );
if ( filePtr == NULL )
{
fprintf( stderr, "unable to open input file!n" );
exit( EXIT_FAILURE );
}
//prompt user for input
printf( "Please enter search string: " );
//read exactly one line of input from user
if ( !get_one_line_of_user_input( search_string, sizeof search_string ) )
{
fprintf( stderr, "input failure!n" );
exit( EXIT_FAILURE );
}
//read exactly one line of input from the input file
//per loop iteration
while ( get_one_line_of_user_input( line, sizeof line ) )
{
char first_name[50];
char last_name[50];
char phone_number[50];
//attempt to parse input
if (
sscanf(
line,
"%49s %49s %49[^n]",
first_name,
last_name,
phone_number
)
!= 3
)
{
fprintf(
stderr,
"WARNING: skipping line due to parse error!n"
);
continue;
}
//verify that none of the fields was too long
if (
strlen( first_name ) == 49
||
strlen( last_name ) == 49
||
strlen( phone_number ) == 49
)
{
//At least one buffer is full, and we have no way
//to determine whether the limit was exceeded or whether
//we are merely at the limit, so we must assume that
//the limit was exceeded.
fprintf(
stderr,
"WARNING: skipping line due to field length "
"limit exceeded!n"
);
continue;
}
//parsing was successful, so we can now search the
//3 individual fields for the search string
if (
strcmp( search_string, first_name ) == 0
||
strcmp( search_string, last_name ) == 0
||
strcmp( search_string, phone_number ) == 0
)
{
//print entire input line of file for user
printf( "%sn", line );
}
}
//cleanup
fclose(filePtr);
}