提问人:ayoub hmani 提问时间:1/29/2023 最后编辑:ayoub hmani 更新时间:2/1/2023 访问量:150
使用 !feof 搜索文件的安全性如何?
How safe is using !feof in searching a file?
问:
我在这里读到,或者更准确地说,在文件中搜索信息时使用是一个坏习惯。feof
!feof
我的理解是,这很糟糕,因为它在调用函数或进程或类似的东西之前从指针读取信息。FILE
在内部有一个 / 循环作为退出条件不是很好吗?do
while
fscanf
!feof
这是我做的一个搜索功能:
typedef struct
{
char lname[20] , fname[20];
int nchildren;
}employee;
void searchemployee(char *filename , char *str)
{
employee e;
FILE *f;
int c;
f = fopen(filename, "r");
if (f == NULL)
printf("file couldn't be loaded\n");
else {
c = 0;
do {
fscanf(f, "%s %s %d\n", e.fname, e.lname, &e.nchildren);
if (strcmp(e.fname, str) == 0)
c = 1;
} while (c == 0 && !feof(f));
if (c != 1)
printf("employee not found\n");
else
printf("employee : %s %s| children : %d\n", e.fname, e.lname, e.nchildren);
}
fclose(f);
}
答:
函数的返回值指定上一个输入操作是否已遇到文件末尾。此函数不指定下一个输入是否会遇到文件末尾。feof
问题
do{
fscanf(f,"%s %s %d\n",e.fname,e.lname,&e.nchildren);
if (strcmp(e.fname,str)==0)
c=1;
}while(c==0 && !feof(f));
是如果由于遇到文件末尾而失败并返回,那么它将不写入任何内容。fscanf
EOF
e.fname
如果这种情况发生在循环的第一次迭代中,则 的内容将是不确定的,后续的函数调用将调用未定义的行为(即您的程序可能会崩溃),除非碰巧包含终止 null 字符。e.fname
strcmp(e.fname,str)
e.fname
如果这不是在第一次迭代中发生,而是在循环的后续迭代中发生,则 的内容将包含上一次循环迭代的内容,因此您将有效地处理两次的最后一次成功调用。e.fname
fscanf
在这种特定情况下,处理两次的最后一次成功调用是无害的,除了会稍微浪费 CPU 和内存资源。但是,在大多数其他情况下,将最后一个输入处理两次将导致程序无法按预期工作。fscanf
有关详细信息,请参阅以下问题:
为什么 “while( !feof(file) )” 总是错的?
如果将循环更改为
for (;;) {
fscanf(f,"%s %s %d\n",e.fname,e.lname,&e.nchildren);
if ( c != 0 || feof(f) )
break;
if (strcmp(e.fname,str)==0)
c=1;
}
这样在循环中间检查循环条件,那么上面提到的问题就会消失。
但是,通常最好检查 的返回值而不是调用 ,例如:fscanf
feof
c = 0;
while ( c == 0 && fscanf(f,"%s %s %d\n",e.fname,e.lname,&e.nchildren) == 3 ) {
if (strcmp(e.fname,str)==0)
c=1;
}
此外,您不需要 flag 变量 。我建议你合并这些线c
if (c!=1)
printf("emplyee not found\n");
else
printf("employee : %s %s| children : %d\n",e.fname,e.lname,e.nchildren);
部分进入循环,如下所示:
void searchemployee( char *filename, char *str )
{
employee e;
FILE *f = NULL;
//attempt to open file
f = fopen( filename, "r" );
if ( f == NULL )
{
printf( "file couldn't be loaded\n" );
goto cleanup;
}
//process one employee record per loop iteration
while ( fscanf( f, "%s %s %d\n", e.fname, e.lname, &e.nchildren ) == 3 )
{
//check whether we found the target record
if ( strcmp(e.fname,str) == 0 )
{
printf(
"employee : %s %s| children : %d\n",
e.fname, e.lname, e.nchildren
);
goto cleanup;
}
}
printf( "employee not found.\n");
cleanup:
if ( f != NULL )
fclose(f);
}
另一个问题是,当使用 with 或 时,通常还应该添加宽度限制,以防止可能的缓冲区溢出。例如,如果字符大小为字符,则应使用限制写入的字节数加上终止 null 字符。%s
scanf
fscanf
e.fname
100
%99s
99
评论
fscanf(f, "%s"...)
无法避免输入时间长于预期时的未定义行为。
employee
e.fname
e.lname
"%s"
scanf
scanf
调用会询问以下问题:“在此流的上一个操作中是否遇到文件结束或错误?feof
如果你习惯于回答这个问题,那很好。但是,您过去常常期望您的下一个操作将从文件中读取数据,这是错误的。上一个操作可能在文件结束之前结束,因此说“否”,但文件中没有剩余任何内容可供读取。feof
feof
feof
标准 C 库中的文件/流函数旨在告诉您它们何时因到达文件末尾而失败。应使用每个函数提供的返回值(或其他指示)来测试问题:
if (3 != fscanf(f, "%s %s %d\n", e.fname, e.lname, &e.nchildren))
{
// Handle fact that fscanf did not read and convert 3 values.
}
int x = getchar();
if (x == EOF)
{
// Handle fact that fscanf did not read and convert 3 values.
}
请注意,调用 And Then 将判断是否遇到文件结束或输入错误,但它不会告诉您是否读取了一些输入并分配了一些值,但随后遇到了文件结束并且没有完成。如果您只读取一件事,您可能会侥幸逃脱,然后是 ,但更复杂的程序可能需要区分部分输入。fscanf
feof
fscanf
fscanf
fscanf
feof
评论
fscanf(f,"%s %s
- 如果第一个有效,但第二个失败怎么办?%s
%s
fscanf
fscanf
feof
fgets
fscanf
fread
feof
ferror
feof()
do / while
fscanf()
fscanf()