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
打印结果:
档文本内容为下面内容时(相比较上面,多出一个空行,即最后一行是空),打印则不正常,输出最后一行不是空,也不是忽略了,而是重复了倒数第二行内容。这是为什么呢?
aaa
bbb
打印结果:
分析:
首先是循环结束条件,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);
打印结果:
Ref: https://stackoverflow.com/questions/1642789/fgets-in-c-repeats-last-line?r=SearchResults