C 用fgets实现EOF
我正在编写一个函数来执行一些身份验证操作。我有一个包含所有C 用fgets实现EOF,c,unix,eof,fgets,C,Unix,Eof,Fgets,我正在编写一个函数来执行一些身份验证操作。我有一个包含所有user\u id:password:flag组合的文件,其结构如下: Users.txt user\u 123:a1b2:0 user\u 124:a2b1:1 user\u 125:a2b2:2 代码如下: int main(){ /*...*/ /*user_id, password retrieving*/ USRPSW* p = malloc(sizeof(USRPSW)); if(p == N
user\u id:password:flag
组合的文件,其结构如下:
Users.txt
user\u 123:a1b2:0 user\u 124:a2b1:1 user\u 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 */
}
/*...*/
}
intmain(){
/*...*/
/*用户id,密码检索*/
USRPSW*p=malloc(sizeof(USRPSW));
if(p==NULL){
fprintf(stderr,“动态分配错误”\n);
退出(退出失败);
}
memset((void*)p,0,sizeof(USRPSW));
如果(usr_psw_read(acc_sock_ds,p->user_id,usr_SIZE)password,psw_SIZE)您可能希望在循环中尝试以下操作:
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标记或文件中有任何错误,循环将终止。我确信这是一种过分的操作,但这些测试对我来说一直都是有效的。fgets()
在到达文件结尾或错误条件时返回空指针
(EOF
是一个宏,指定在类似条件下由某些其他函数返回的值;它不仅仅是短语“文件结束”的缩写。)
您正在忽略由fgets()
返回的结果。请不要这样做
请注意,仅检查feof(fd)
并不能满足您的要求。feof()
如果到达文件末尾,将返回一个真实的结果。如果遇到错误,feof()
仍然返回false,如果使用feof(),您将得到一个无限循环
来决定何时完成。在读取输入失败之前,它不会返回true
大多数C输入函数都会返回一些特殊值来表示没有什么可读的了。对于fgets()
它是NULL
,对于fgetc()
它是EOF
,等等。如果您愿意,可以调用feof()
和/或ferror()
之后,确定没有更多内容可读取的原因。如果未读取任何字符就到达文件末尾,fgets
必须返回NULL
。无论如何,您可以检查feof(fd)
在fgets
之后,没有读取任何内容。恐怕没有设置EOF。我只写了一个包含记录的文件。我还应该显式地设置EOF?怎么做?这不是关于读取时到达文件结尾吗?您没有设置EOF,如果到达文件结尾,下次尝试读取时将在*fd
,因此如果一切正常,那么feof(fd)
将返回true。如果一切都不正常,嗯。EOF
是一种条件,而不是水流的一部分。想象水流是来自水龙头的水。当你打开水龙头直到它耗尽时,你会得到更多的水(另一种颜色?)要发出没有水的信号?除非您要使用超过,哦,8kib的数据,否则您最好通过使用char-usr\u-psw\line[usr\u SIZE+psw\u SIZE+3+1];
而不是动态内存分配来避免malloc()
的开销和泄漏的可能性,您不会返回已分配的数组,因此这不是这次进行分配的原因-在函数中,这可能是一个很好的原因。(笑着说)我刚才的回答中不是这样说了吗?@Stevevallier或多或少,但我试着更明确地说明基本概念。这是最好的(IMO)对循环条件使用while(fgets(usr\u psw\u line,sizeof(usr\u psw\u line,fd)!=0)
。在读取之前确实不需要将内存归零。在那里使用ferror()
或feof()
进行测试没有任何好处(因为只有当测试从fgets()返回时,它们才会计算为true)
返回NULL;因此,它们永远不会导致循环退出)。同意。我试图保留尽可能多的原始代码,以便只有直接回答问题的部分是清楚的。但我完全按照您在我的所有文件读取循环中描述的做。@JonathanLeffler“使用ferror()进行测试”…仅当对fgets()返回的测试返回NULL“-->我认为在极端情况下不会这样。ferror()
返回可能在调用fgets()
之前设置的错误标志的状态。fgets()
没有清除该标志,因此fgets()
可能返回非NULL
但ferror()
返回true。@chux:我的论点基于这样一个命题,即如果在调用fgets()
时设置了错误标志,fgets()
必须失败。然而,我实际上在标准中找不到要求这样做的措辞,尽管我会惊讶地发现一个实现没有这样做。如果跟踪流的状态,除非使用cleaerr()
。存在一个难以置信的边缘情况。测试feof()
是毫无意义的。我坚持每天使用我的观察。如果我担心流的错误状态,我会在进入函数时使用ferror()
。@JonathanLeffler同意日常使用,feof()
,模糊性和良好的代码将测试ferror()
,但吸引我注意的是。fgets()
如果设置了流的错误指示器,则不会自动返回NULL
,但如果发生读取错误(设置错误指示器会产生副作用),则会返回NULL
。