使用 fgets 达到 EOF
Posted
技术标签:
【中文标题】使用 fgets 达到 EOF【英文标题】:Reaching EOF with fgets 【发布时间】:2013-03-07 05:15:48 【问题描述】:我正在编写一个执行某些身份验证操作的函数。我有一个包含所有user_id:password:flag
夫妇的文件,其结构如下:
Users.txt
user_123:a1b2:0 user_124:a2b1:1 user_125:a2b2:2
这是代码:
int main()
/*...*/
/*user_id, password retrieving*/
USRPSW* p = malloc(sizeof(USRPSW));
if(p == NULL)
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
memset((void*)p, 0, sizeof(USRPSW));
if(usr_psw_read(acc_sock_ds, p->user_id, USR_SIZE) <= 0)
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
if(usr_psw_read(acc_sock_ds, p->password, PSW_SIZE) <= 0)
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
/*Authentication through user_id, password*/
FILE *fd;
fd = fopen(USERSFILE, "r");
if(fd == NULL)
fprintf(stderr, "Users file opening error\n");
exit(EXIT_FAILURE);
char *usr_psw_line = malloc(USR_SIZE+PSW_SIZE+3+1);
if(usr_psw_line == NULL)
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
while(1)
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd);
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
/*...*/
如何管理 EOF 到达?我看到当达到 EOF 时 fgets
不再编辑 usr_psw_line 但既不返回 NULL 指针。如果达到 EOF,则意味着在用户文件中找不到匹配项并且循环中断。
谁能给我一些提示或建议?
【问题讨论】:
如果在没有读取任何字符的情况下到达文件末尾,fgets
必须返回NULL
。无论如何,您可以在 fgets
没有阅读任何内容之后检查 feof(fd)
。
恐怕没有设置EOF。我只写了一个里面有记录的文件。我还应该明确设置EOF吗?你是怎么做到的?
不就是读到文件尾吗?您不设置 EOF,如果到达文件末尾,则下一次尝试读取文件将在 *fd
中设置标志,因此如果一切正常,feof(fd)
将返回 true。如果一切都无法正常工作,嗯。
EOF
是一个条件,而不是流的一部分。想象溪流是水龙头里的水。当您打开水龙头直到它耗尽时,您是否会得到更多水(另一种颜色?)以表示没有更多水了?
【参考方案1】:
fgets()
在到达文件结尾或错误条件时返回一个空指针。
(EOF
是一个宏,它指定某些其他函数在类似条件下返回的值;它不仅仅是短语“文件结尾”的缩写。)
您忽略了fgets()
返回的结果。不要那样做。
请注意,仅检查 feof(fd)
不会满足您的要求。如果您已到达文件末尾,feof()
将返回 true 结果。如果您遇到错误,feof()
仍然返回 false,如果您使用 feof()
来决定何时完成,您就会陷入无限循环。并且直到 在您未能读取输入后它才会返回 true。
大多数 C 输入函数都会返回一些特殊值,以表明没有更多可读取的内容。对于fgets()
,它是NULL
,对于fgetc()
,它是EOF
,等等。如果您愿意,您可以在之后致电feof()
和/或ferror()
来确定为什么没有什么可阅读的了。
【讨论】:
(笑着说)我之前的回答不是说的吗? @SteveValliere 或多或少,但我试图更明确地了解基本概念。【参考方案2】:你可能想在你的循环中尝试这样的事情:
while(1)
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
if( !fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd)
|| ferror( fd ) || feof( fd ) )
break;
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
使用额外的代码,如果fgets
返回 NULL(没有更多数据要读取)或者如果您读取了 EOF 标记或文件上有任何错误,则循环将终止。我敢肯定这是矫枉过正,但这些测试一直对我有用。
【讨论】:
最好 (IMO) 使用while (fgets(usr_psw_line, sizeof(usr_psw_line), fd) != 0)
作为循环条件。在读取之前确实不需要将内存归零。并且在那里使用ferror()
或feof()
进行测试没有任何好处(因为如果从fgets()
返回的测试返回NULL,它们只会评估为true;因此,它们永远不会导致循环退出)。跨度>
同意。我试图尽可能多地保留原始代码,以便直接回答问题的部分清楚。但我完全按照你在我所有的文件读取循环中描述的那样做。
@chux:我的论点是基于如果在调用fgets()
时设置了错误标志,fgets()
必须失败的命题。但是,我实际上无法在标准中找到强制执行此操作的措辞,尽管我会惊讶地发现没有那样做的实现。如果您跟踪流的状态,除非您使用clearerr()
,否则您将不会在失败后使用它。有一个难以置信的边缘案例可用。测试feof()
毫无意义。我坚持我对日常使用的观察。如果我担心流的错误状态,我会在函数入口处使用ferror()
。
示例中的代码“sizeof(USR_SIZE+PSW_SIZE+3+1)”总是计算整数的大小 - 在许多现代机器上,它总是 4,无论USR_SIZE 和 PSW_SIZE——“sizeof(42)”(或任何其他较小的数字)将返回相同的值。我猜封闭的“sizeof(...)”是一个错误。无论如何,将整个缓冲区归零是多余的——如果有人怀疑 fgets() 的行为——一个基于 C 字符串的函数——那么 "usr_psw_line[0] = '\0';"就足够了。
如果要使用 feof() 和/或 ferror(),它们可能应该在调用 fgets() 之前调用 - 以确定给定文件是否为 已经处于先前活动的 EOF 或错误状态 - 或 在 fgets() 返回 NULL,以确定 fgets() 返回 NULL 的原因。在当前的形式中,他们除了误导查看代码的人外,几乎没有做任何事情。以上是关于使用 fgets 达到 EOF的主要内容,如果未能解决你的问题,请参考以下文章