1.fgets描述
linux下man fgets查手册知道,fgets()会一致读到文件EOF或者一个新行。换行符(”
“)会放入fgets指定缓冲区,且末尾后会加入””;

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read , it is stored into buffer. A terminating null byte ("") is store after the last character in the buffer.

 
2.fgets, gets区别
gets()和fgets()都是可以从键盘输入字符串,遇到换行符或EOF为止。那么它们有什么区别呢?
1)gets()没有指定输入字符大小,会无限读取。但是不安全,要求程序员自行控制缓冲区大小;fgets()会要求指定输入字符大小,不会无限读取,更安全。
 
e.g. 假设输入的字符串长度 > s缓存长度,也不会报错,但是可能会溢出。溢出不一定会报错,要看溢出的RAM空间是否会影响到别的进程。

char s[2];
gets(s);
printf("%s", s);

e.g. 输入字符串长度不能超过指定读取的长度,而且最后一个byte会用于填充”(fgets指定size的最后1个byte,而非缓存中最后1个byte才填充 ”)。 如果超过,超过的内容会留在输入流中。

char s[2];
fget(s, sizeof(s), stdin);
printf("%s", s);

3.fgets最后一行重复问题
当最后一行为空时,fgets会重复倒数第二行数据。
 
e.g. fgets读取ASCII文本。 

 1 void read_file1()
 2 {
 3     FILE *fp ;
 4     char *fileName = "./test.txt"; //待读取文本文件
 5  
 6     if((fp = fopen(fileName, "r")) == NULL)
 7     {
 8         printf("file %s does not exist.
", fileName);
 9         return -1;
10     }
11  
12     char s[256] = {0};
13     int lineNum = 0;
14  
15     while(!feof(fp))
16     {
17         fgets(s, sizeof(s), fp);
18  
19         printf("%d: %s
", lineNum, s);
20         printf("len = %d
", strlen(s));
21         printf("last char's ASCII code = %d
", s[strlen(s) - 1]);
22  
23         lineNum ++;
24     }
25  
26     fclose(fp);
27 }

 

当文本文件内容为下面内容时,打印正常

aaa
bbb

打印结果:
fgets读取文件最后一行重复问题-编程知识网fgets读取文件最后一行重复问题-编程知识网
 
档文本内容为下面内容时(相比较上面,多出一个空行,即最后一行是空),打印则不正常,输出最后一行不是空,也不是忽略了,而是重复了倒数第二行内容。这是为什么呢?

aaa
bbb

打印结果:
fgets读取文件最后一行重复问题-编程知识网fgets读取文件最后一行重复问题-编程知识网
 
分析:
首先是循环结束条件,feof(fp)是检测流上的文件结束符,如果文件结束,则返回非0;如果文件未结束,则返回0。
第1行”bbb
“读完以后,此时并不知道文件结尾,s=”bbb
“,会继续读下一行。
第2行””(空)会读到文件结尾EOF,正常情况会将”用于填入空串后,为何还会填充前面一行内容呢?
这是因为用fgets获取最后一行(空行)失败,而抓取的s数据会在检查到已经到文件结尾(循环结束条件)之前,就打印了。也就是说打印内容其实是无效的,实际上fgets并未影响到缓存s内容,也就是倒数第二行内容。
 
改善:将打印数据内容放到检查是否已经碰到文件末尾之后

FILE *fp;
char s[256];
while(true)
{
    fgets(s, sizeof(s), fp);
    if(feof(fp))
    {
        break;
    }
    
    printf("%s", s);
}
 
fclose(fp);

打印结果:
fgets读取文件最后一行重复问题-编程知识网fgets读取文件最后一行重复问题-编程知识网
 
Ref: https://stackoverflow.com/questions/1642789/fgets-in-c-repeats-last-line?r=SearchResults