我一直在撰寫一個程式來將資料寫入文本檔案并在 c 中練習資料處理,并從那里找到資料,每個資料都存盤為行。有行,資料是逐行存盤的,如:
學生姓名 學生姓 學生電話等
當我輸入“學生姓名”時,它開始列印而不列印姓名本身,列印后面的內容,如果我搜索姓氏也會發生同樣的情況,只會列印出電話。
#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 number\n");
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
uj5u.com熱心網友回復:
而不是錯誤地使用feof()和fscanf(filePtr,"%s", ...錯誤地讀取一行。用于fgets()讀取檔案的一行并轉換為字串。
測驗 的回傳值
fgets()以查看是否有輸入。用于
strstr()在 中查找匹配的子字串string。
例子:
while (fgets(string, sizeof string, filePtr)) {
if (strstr(string, char_input)){
fputs(string, stdout);
}
}
uj5u.com熱心網友回復:
該函式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 );
}
}
這樣就解決了上面提到的不檢查回傳值的問題fscanf。但是,根據確切的輸入,函式也可能fgets由于遇到檔案結尾而失敗。fgets因此,如果您的程式也檢查函式的回傳值,而不是簡單地假設函式成功,那會更好。
另一個問題是線路
puts(string);
只會列印 的內容string,即" Brooks 865 965 55". 但是,您還想要 print "Andrew",它已被函式呼叫讀取fscanf但同時已被fgets函式呼叫覆寫。最簡單的解決方案是在它被覆寫之前列印它。"Brooks"但是,如果用戶搜索而不是,這將不起作用"Andrew",因為該單詞"Andrew"在之前的回圈迭代中已經被丟棄。這是因為在回圈中呼叫fscanf(filePtr,"%s",string)不會在每次回圈迭代時讀取一行輸入,而是在每次回圈迭代時讀取一個單詞(這不是很有意義)。
使用逐字讀取輸入檔案的另一個后果fscanf(filePtr,"%s",string)是您將無法找到電話號碼的匹配項"865 965 55"。這是因為您的程式將首先"865"從輸入檔案中讀取并確定此“單詞”與搜索字串不同。然后它將讀取"965"并確定相同的內容。它會為"55".
最好的解決方案可能是重新設計您的回圈,以便每次回圈迭代始終準確讀取一行輸入,而不是每次回圈迭代僅讀取一個單詞。讀入一行輸入后,您可以使用函式將其拆分為“名字”、“姓氏”和“電話號碼”來決議該行sscanf。
#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")] = '\0';
//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,
"Is Is I[^\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")] = '\0';
//print entire input line of file for user
printf( "%s\n", 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 = '\0';
}
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,
"Is Is I[^\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( "%s\n", line );
}
}
//cleanup
fclose(filePtr);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/413526.html
標籤:
