這篇文章要探討的是“fgets()函數的詳解以及使用時需要注意的一些細節”。涉及fgets()函數的應用和需要注意的問題。屬於C語言基礎篇(持續更新
)。
fgets()(函數原型:char *fgets(char *restrict str, int size, FILE *restrict stream))
這個函數原型不太好看出個所以然來,可以理解為(char *fgets(“容器的地址”, “容器的大小”, “從哪里讀取”))
一般用法:
char a[100] = {0};
fgets(a, 100, stdin);
通俗來講的話,fgets()
函數的作用就是用來讀取一行數據的。但要詳細且專業的說的話,fgets()
函數的作用可以這么解釋:從第三個參數指定的流中讀取最多第二個參數大小的字符到第一個參數指定的容器地址中。在這個過程中,在還沒讀取夠第二個參數指定大小的字符前,讀取到換行符'\n'
或者需要讀取的流中已經沒有數據了。則提前結束,並把已經讀取到的字符存儲進第一個參數指定的容器地址中。
在正常情況下fgets()
函數的返回值和它第一個參數相同。即讀取到數據后存儲的容器地址。但是如果讀取出錯或讀取文件時文件為空,則返回一個空指針。
fgets()
函數的運行流程大概是這樣子的:
當系統調用這個函數的時,系統便會阻塞等待用戶的輸入,直到用戶輸入回車符’\n’才返回程序。然后用戶輸入的內容會被系統放進輸入緩存區里面,fgets()函數便會進來讀取其“第二個參數減1(為什么減1后面說)”個字節存進它第一個參數指向的內存地址中,如果在還沒讀取夠需要的字節大小前讀取到換行符’\n’則提前返回。
fgets()函數的注意事項1
fgets()
函數的最大讀取大小是其“第二個參數減1
”,這是由於字符串是以’\0’
為結束符的,fgets()
為了保證輸入內容的字符串格式
,當輸入的數據大小超過了第二個參數
指定的大小的時候,fgets()
會僅僅讀取前面的“第二個參數減1
”個字符,而預留1個字符
的空間來存儲字符串結束符’\0’
。
測試代碼:
#include <stdio.h>
int main(void)
{
char a[10] = {0};
printf("你的輸入:");
fgets(a, 4, stdin);
//printf("%s\n", a);//下面這句的輸出和這句是一樣的
printf("printf(\"%%s\\n\", a)%c==>%s\n", ';', a);
return 0;
}
運行效果:
在這個例子中,fgets()
的第二個參數是4
,所以它最多只能存儲輸入的(4-1 = 3)
個字符進第一個參數指向的地址空間里面。輸入“abcde
”,數組a[]中只有“abc
”。
fgets()函數的注意事項2
在fgets()
函數的眼里,換行符’\n’
也是它要讀取的一個普通字符
而已。在讀取鍵盤輸入的時候會把最后輸入的回車符也存進數組里面,即會把’\n’也存進數組里面,而又由於字符串本身會是以’\0’
結尾的。所以在輸入字符個數沒有超過第二個參數指定大小
之前,你輸入n
個字符按下回車輸入,fgets()
存儲進第一個參數指定內存地址的是n+2
個字節。最后面會多出一個’\n’
和一個’\0’
,而且’\n’
是在’\0’
的前面一個(\n\0
)。
測試代碼:
#include <stdio.h>
int main(void)
{
char a[10] = {0};
printf("你的輸入:");
fgets(a, 10, stdin);
//printf("%s\n", a);//下面這句的輸出和這句是一樣的
printf("printf(\"%%s\\n\", a)%c==>%s\n", ';', a);
for(int i=0; i<10; i++)
{
if(a[i] == '\n')
printf("a[%d]是換行符'\\n'\n", i);
if(a[i] == '\0')
printf("a[%d]是字符串結束符'\\0'\n", i);
}
return 0;
}
運行效果:
在這個例子中,由於輸入的字符小於參數2
指定的最大讀取字符數
,所以fgets()
函數會把換行符’\n’
也儲存進數組a[]
里面,在運行界面的第三行哪里換了兩次行
,就是由於這個多出來的換行符’\n’和我輸出代碼中的換行符’\n’共同作用的結果。
fgets()函數的注意事項3
fgets()
函數只負責讀取
,並不會事先清空參數1
指向的地址內存。讀取到的字節會覆蓋原地址儲存,但沒有覆蓋到的內容還是保持原樣。
測試代碼:
#include <stdio.h>
int main(void)
{
char a[10] = {'1','1','1','1','1','1','1','1','1','1'};
printf("你的輸入:");
fgets(a, 10, stdin);
//printf("%s\n", a);//下面這句的輸出和這句是一樣的
printf("printf(\"%%s\\n\", a)%c==>%s\n", ';', a);
for(int i=0; i<10; i++)
{
if(a[i] == '\n' || a[i] == '\0')
printf("a[%d] = '\\%c'", i, a[i]=='\n'?'n':'0');
else
printf("a[%d] = %c", i, a[i]);
printf("\n");
}
return 0;
}
運行結果:
fgets()函數的注意事項4
在用fgets()
函數讀取鍵盤輸入的時候,如果輸入多於其“第二個參數減1
”個字符大小的數據,fgets()
只會讀取走前”第二個參數減1
”個字符,多余的字符殘留在輸入緩存區里面。如果不清空,可能會影響下次輸入。
測試代碼:
#include <stdio.h>
int main(void)
{
char a[4] = {0};
char b[10] = {0};
printf("存進a的輸入:");
fgets(a, 4, stdin);
for(int i=0; i<4; i++)
printf("a[%d] = %c\n", i, a[i]);
printf("存進b的輸入:");
fgets(b, 10, stdin);
printf("這里沒有阻塞等待輸入,而是直接跳過了\n");
//printf("%s", a);//下面這句的輸出和這句是一樣的
printf("printf(\"%%s\", b)%c==>%s", ';', b);
return 0;
}
運行結果:
在這個例子中,輸入“abcde
”之后,數組a[]
讀取走“abc
”之后,代碼運行到第11行的時候並沒有停下來等待用戶的輸入,而是直接讀取了還留在緩存區里面的“de\n
”,讀取到‘\n’
之后返回,所以我最后一行的輸出代碼中並沒有加上換行符’\n’
,因為數組b[]
中已經包含有換行符’\n’
了。
fgets()函數的注意事項5
遇到再更新。。。
原博客始發於CSDN,在如今博客界的轉載抄襲泛濫的環境下,原創不易,點個贊再走唄。以下是博客首頁的鏈接。