1.fgets描述
linux下man fgets查手冊知道,fgets()會一直讀到文件EOF或者一個新行。換行符("\n")會放入fgets指定緩沖區,且末尾后會加入"\0";
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 ("\0") 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會用於填充'\0'(fgets指定size的最后1個byte,而非緩存中最后1個byte才填充 '\0')。 如果超過,超過的內容會留在輸入流中。
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.\n", 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\n", lineNum, s); 20 printf("len = %d\n", strlen(s)); 21 printf("last char's ASCII code = %d\n", s[strlen(s) - 1]); 22 23 lineNum ++; 24 } 25 26 fclose(fp); 27 }
當文本文件內容為下面內容時,打印正常
aaa
bbb
打印結果:


檔文本內容為下面內容時(相比較上面,多出一個空行,即最后一行是空),打印則不正常,輸出最后一行不是空,也不是忽略了,而是重復了倒數第二行內容。這是為什么呢?
aaa
bbb
打印結果:


分析:
首先是循環結束條件,feof(fp)是檢測流上的文件結束符,如果文件結束,則返回非0;如果文件未結束,則返回0。
第1行"bbb\n"讀完以后,此時並不知道文件結尾,s="bbb\n\0",會繼續讀下一行。
第2行""(空)會讀到文件結尾EOF,正常情況會將'\0'用於填入空串后,為何還會填充前面一行內容呢?
這是因為用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);
打印結果:

