fgets()函數(shù)的詳解以及使用時(shí)需要注意的一些細(xì)節(jié)
一般用法:
char a[100] = {0};
fgets(a, 100, stdin);
通俗來(lái)講的話,fgets()
函數(shù)的作用就是用來(lái)讀取一行數(shù)據(jù)的。但要詳細(xì)且專(zhuān)業(yè)的說(shuō)的話,fgets()
函數(shù)的作用可以這么解釋?zhuān)簭牡谌齻€(gè)參數(shù)指定的流中讀取最多第二個(gè)參數(shù)大小的字符到第一個(gè)參數(shù)指定的容器地址中。在這個(gè)過(guò)程中,在還沒(méi)讀取夠第二個(gè)參數(shù)指定大小的字符前,讀取到換行符'\n'
或者需要讀取的流中已經(jīng)沒(méi)有數(shù)據(jù)了。則提前結(jié)束,并把已經(jīng)讀取到的字符存儲(chǔ)進(jìn)第一個(gè)參數(shù)指定的容器地址中。
在正常情況下fgets()
函數(shù)的返回值和它第一個(gè)參數(shù)相同。即讀取到數(shù)據(jù)后存儲(chǔ)的容器地址。但是如果讀取出錯(cuò)或讀取文件時(shí)文件為空,則返回一個(gè)空指針。
fgets()
函數(shù)的運(yùn)行流程大概是這樣子的:
當(dāng)系統(tǒng)調(diào)用這個(gè)函數(shù)的時(shí),系統(tǒng)便會(huì)阻塞等待用戶的輸入,直到用戶輸入回車(chē)符’\n’才返回程序。然后用戶輸入的內(nèi)容會(huì)被系統(tǒng)放進(jìn)輸入緩存區(qū)里面,fgets()函數(shù)便會(huì)進(jìn)來(lái)讀取其“第二個(gè)參數(shù)減1(為什么減1后面說(shuō))”個(gè)字節(jié)存進(jìn)它第一個(gè)參數(shù)指向的內(nèi)存地址中,如果在還沒(méi)讀取夠需要的字節(jié)大小前讀取到換行符’\n’則提前返回。
fgets()函數(shù)的注意事項(xiàng)1
fgets()
函數(shù)的最大讀取大小是其“第二個(gè)參數(shù)減1
”,這是由于字符串是以’\0’
為結(jié)束符的,fgets()
為了保證輸入內(nèi)容的字符串格式
,當(dāng)輸入的數(shù)據(jù)大小超過(guò)了第二個(gè)參數(shù)
指定的大小的時(shí)候,fgets()
會(huì)僅僅讀取前面的“第二個(gè)參數(shù)減1
”個(gè)字符,而預(yù)留1個(gè)字符
的空間來(lái)存儲(chǔ)字符串結(jié)束符’\0’
。
測(cè)試代碼:
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;
}
運(yùn)行效果:

在這個(gè)例子中,fgets()
的第二個(gè)參數(shù)是4
,所以它最多只能存儲(chǔ)輸入的(4-1 = 3)
個(gè)字符進(jìn)第一個(gè)參數(shù)指向的地址空間里面。輸入“abcde
”,數(shù)組a[]中只有“abc
”。
fgets()函數(shù)的注意事項(xiàng)2
在fgets()
函數(shù)的眼里,換行符’\n’
也是它要讀取的一個(gè)普通字符
而已。在讀取鍵盤(pán)輸入的時(shí)候會(huì)把最后輸入的回車(chē)符也存進(jìn)數(shù)組里面,即會(huì)把’\n’也存進(jìn)數(shù)組里面,而又由于字符串本身會(huì)是以’\0’
結(jié)尾的。所以在輸入字符個(gè)數(shù)沒(méi)有超過(guò)第二個(gè)參數(shù)指定大小
之前,你輸入n
個(gè)字符按下回車(chē)輸入,fgets()
存儲(chǔ)進(jìn)第一個(gè)參數(shù)指定內(nèi)存地址的是n+2
個(gè)字節(jié)。最后面會(huì)多出一個(gè)’\n’
和一個(gè)’\0’
,而且’\n’
是在’\0’
的前面一個(gè)(\n\0
)。
測(cè)試代碼:
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]是字符串結(jié)束符'\\0'\n", i);
} return 0;
}
運(yùn)行效果:

在這個(gè)例子中,由于輸入的字符小于參數(shù)2
指定的最大讀取字符數(shù)
,所以fgets()
函數(shù)會(huì)把換行符’\n’
也儲(chǔ)存進(jìn)數(shù)組a[]
里面,在運(yùn)行界面的第三行哪里換了兩次行
,就是由于這個(gè)多出來(lái)的換行符’\n’和我輸出代碼中的換行符’\n’共同作用的結(jié)果。
fgets()函數(shù)的注意事項(xiàng)3
fgets()
函數(shù)只負(fù)責(zé)讀取
,并不會(huì)事先清空參數(shù)1
指向的地址內(nèi)存。讀取到的字節(jié)會(huì)覆蓋原地址儲(chǔ)存,但沒(méi)有覆蓋到的內(nèi)容還是保持原樣。
測(cè)試代碼:
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;
}
運(yùn)行結(jié)果:

fgets()函數(shù)的注意事項(xiàng)4
在用fgets()
函數(shù)讀取鍵盤(pán)輸入的時(shí)候,如果輸入多于其“第二個(gè)參數(shù)減1
”個(gè)字符大小的數(shù)據(jù),fgets()
只會(huì)讀取走前”第二個(gè)參數(shù)減1
”個(gè)字符,多余的字符殘留在輸入緩存區(qū)里面。如果不清空,可能會(huì)影響下次輸入。
測(cè)試代碼:
int main(void){ char a[4] = {0}; char b[10] = {0}; printf("存進(jìn)a的輸入:");
fgets(a, 4, stdin); for(int i=0; i<4; i++) printf("a[%d] = %c\n", i, a[i]); printf("存進(jìn)b的輸入:");
fgets(b, 10, stdin); printf("這里沒(méi)有阻塞等待輸入,而是直接跳過(guò)了\n"); //printf("%s", a);//下面這句的輸出和這句是一樣的
printf("printf(\"%%s\", b)%c==>%s", ';', b); return 0;
}
運(yùn)行結(jié)果:

在這個(gè)例子中,輸入“abcde
”之后,數(shù)組a[]
讀取走“abc
”之后,代碼運(yùn)行到第11行的時(shí)候并沒(méi)有停下來(lái)等待用戶的輸入,而是直接讀取了還留在緩存區(qū)里面的“de\n
”,讀取到‘\n’
之后返回,所以我最后一行的輸出代碼中并沒(méi)有加上換行符’\n’
,因?yàn)閿?shù)組b[]
中已經(jīng)包含有換行符’\n’
了。
fgets()函數(shù)的注意事項(xiàng)5
遇到再更新。。。?