C語(yǔ)言中scanf函數(shù)與空格回車的用法說(shuō)明
眾所周知,C語(yǔ)言中的scanf函數(shù)的作用是從標(biāo)準(zhǔn)輸入設(shè)備(通常是鍵盤)讀取輸入值,并存儲(chǔ)到參數(shù)列表中指針?biāo)赶虻膬?nèi)存單元。
下面從幾個(gè)方面說(shuō)一下一些稍微細(xì)節(jié)的東西。下面的實(shí)驗(yàn)都在vc6.0中通過(guò)。
1、scanf的返回值
scanf通常返回的是成功賦值(從標(biāo)準(zhǔn)輸入設(shè)備賦值到參數(shù)列表所指定的內(nèi)存區(qū)域)的數(shù)據(jù)項(xiàng)數(shù),如果出錯(cuò)或是遇到end of file(注意,如果想從鍵盤輸入EOF,在windows的DOS窗口用Ctrl+Z 或F6;在UNIX系統(tǒng)上,用CTRL+D。),則返回EOF,比如:
scanf("%d%d", &x, &y);
如果x和y都被成功讀入,那么scanf的返回值就是2;
如果只有x被成功讀入,返回值為1;
如果x和y都未被成功讀入,返回值為0;
如果遇到錯(cuò)誤或遇到end of file,返回值為EOF。
2、scanf的處理機(jī)制
scanf以刪除的方式從緩沖區(qū)讀入數(shù)據(jù)(來(lái)自標(biāo)準(zhǔn)輸入設(shè)備的數(shù)據(jù)存儲(chǔ)在緩沖區(qū)),也就是說(shuō),scanf從緩沖區(qū)讀入一個(gè)數(shù)據(jù)項(xiàng),該數(shù)據(jù)項(xiàng)在緩沖區(qū)中就被清除掉了。
而如果scanf需要讀取一個(gè)數(shù)據(jù)項(xiàng),返現(xiàn)緩沖區(qū)當(dāng)前是空的,那么程序就會(huì)在scanf代碼處阻塞,等待用戶輸入,scanf函數(shù)接收到相應(yīng)的數(shù)據(jù)項(xiàng)之后,在緩沖區(qū)中將這一數(shù)據(jù)項(xiàng)清除,scanf函數(shù)返回,程序繼續(xù)執(zhí)行。
3、scanf對(duì)不同類型輸入的處理方式
首先,要清除一個(gè)概念:空白字符(white space)。一般,程序中所指的空白字符是指空格(space),回車(enter)和指標(biāo)符(table)。
3.1 整數(shù)%d
對(duì)于整型數(shù)據(jù)的輸入,也就是說(shuō)"%d"類型的輸入,scanf默認(rèn)的分割符是所有的空白字符(空格,回車和指標(biāo)符都行)。
也就是說(shuō)如果一個(gè)scanf函數(shù)中出現(xiàn)scanf("%d%d",&a,&b),那么用任何一個(gè)空白字符來(lái)分隔兩個(gè)整數(shù)a,b的值,變量a,b都可以接收到正確的輸入。
另外,要注意的是,scanf對(duì)于數(shù)字輸入,會(huì)忽略輸入數(shù)據(jù)項(xiàng)前面的空白字符。下面是例1:
Code: #include<stdio.h> int main() { int a,b; printf("Input the value of a and b:"); while(scanf("%d%d",&a,&b)!=EOF) { printf("a=%d,b=%d\n",a,b); printf("Input the value of a and b:"); } return 0; } Output: Input the value of a and b:123 456 a=123,b=456 Input the value of a and b:123 456 a=123,b=456 Input the value of a and b:123 456 a=123,b=456 Input the value of a and b: 123 456 a=123,b=456 Input the value of a and b: 123 456 a=123,b=456 Input the value of a and b: 123 456 a=123,b=456 Input the value of a and b:^Z Press any key to continue
3.2 字符串%s
scanf對(duì)于字符串輸入的處理和對(duì)整數(shù)類似,會(huì)忽略前導(dǎo)的空白字符,而且默認(rèn)的分隔符是所有的空白字符。但是,要注意的是,由于C語(yǔ)言中,沒有string類型,都是用char型數(shù)組來(lái)表示。
因此,scanf會(huì)為每一個(gè)輸入的字符串最后加一個(gè)‘\0'。下面是一個(gè)例子,可以看出scanf這貨的邊界控制還是要小心。
如下例2。
#include<stdio.h> int main() { char a[5],b[5]; int i; printf("Input the value of a and b:"); while(scanf("%s%s",a,b)!=EOF) { printf("a=%s,b=%s\n",a,b); for(i=0;i<5;i++) printf("%d:(%c) ",a[i],a[i]); printf("\n"); for(i=0;i<5;i++) printf("%d:(%c) ",b[i],b[i]); printf("\n"); printf("Input the value of a and b:"); } return 0; }
運(yùn)行結(jié)果:
3.3 字符%c
scanf在處理對(duì)字符數(shù)據(jù)的輸入時(shí),既不會(huì)忽略前導(dǎo)空白字符,默認(rèn)也沒有任何分隔字符。所有的字符,包括空白字符都會(huì)被當(dāng)成輸入字符。
下面是例3。
#include<stdio.h> int main() { char a ,b ; printf("Input the value of a and b:"); while(scanf("%c%c",&a,&b)!=EOF) { printf("a=%c,b=%c\n",a,b); printf("Input the value of a and b:"); } return 0; }
運(yùn)行結(jié)果:
可以看出,在對(duì)字符數(shù)據(jù)輸入的時(shí)候,由于緩沖區(qū)中有回車空格等數(shù)據(jù),會(huì)導(dǎo)致輸入數(shù)據(jù)比較詭異,為了解決這個(gè)問(wèn)題,有以下方法:
(1) 清空緩沖區(qū)
在微軟系統(tǒng)中,有一個(gè)名為fflush(stdin)的函數(shù),可以用來(lái)清空緩沖區(qū),
如下例4。
#include<stdio.h> int main() { char a ,b ; printf("Input the value of a and b:"); while(scanf("%c%c",&a,&b)!=EOF) { printf("a=%c,b=%c\n",a,b); fflush(stdin); printf("Input the value of a and b:"); } return 0; }
運(yùn)行結(jié)果:
(2)將緩沖區(qū)的數(shù)據(jù)讀出來(lái)
有的編譯系統(tǒng)并沒有定義stdin的fflush操作,這個(gè)時(shí)候,可以把緩沖區(qū)中的數(shù)據(jù)讀出來(lái),有如下幾種可行的方法:
1) getchar()
將例4中的fflush(stdin);語(yǔ)句換成
char c;
while((c=getchar())!='\n'&&c!=EOF);
運(yùn)行效果和上面的相同。
2) gets()
char* gets(char* buffer)從stdin流中讀取字符串,直至接受到換行符或EOF時(shí)停止,并將讀取的結(jié)果存放在buffer指針?biāo)赶虻淖址麛?shù)組中。換行符不作為讀取串的內(nèi)容,讀取的換行符被轉(zhuǎn)換為null值,并由此來(lái)結(jié)束字符串。
讀入成功,返回與參數(shù)buffer相同的指針;讀入過(guò)程中遇到EOF(End-of-File)或發(fā)生錯(cuò)誤,返回NULL指針。
所以在遇到返回值為NULL的情況,要用ferror或feof函數(shù)檢查是發(fā)生錯(cuò)誤還是遇到EOF。
要注意的是gets函數(shù)可以無(wú)限讀取,不會(huì)判斷上限,所以應(yīng)該確保buffer的空間足夠大,以便在執(zhí)行讀操作時(shí)不發(fā)生溢出。如果溢出,多出來(lái)的字符將被寫入到堆棧中,這就覆蓋了堆棧原先的內(nèi)容,破壞一個(gè)或多個(gè)不相關(guān)變量的值。
將例4中的fflush(stdin);語(yǔ)句換成
char c[10];
gets(c);
運(yùn)行效果也和上面的相同。
4、在stackoverflow上看到的一個(gè)問(wèn)題
#include<stdio.h> #include<stdlib.h> #include<string.h> char *method1(void) { static char a[4]; scanf ("%s\n", a); return a; } int main(void) { char *h = method1(); printf ("%s\n", h); return 0; }
運(yùn)行結(jié)果:
ab cd ab Press any key to continue
可以發(fā)現(xiàn),輸如兩次之后才會(huì)輸出。這個(gè)現(xiàn)象比較詭異,原因如下:
White space (such as blanks, tabs, or newlines) in the format string match any amount of white space, including none, in the input. Everything else matches only itself.
Thus with scanf ("%s\n", a) it will scan for a string followed by optional white space. Since after the first newline more whitespace may follow, scanf is not done after the first newline and looks what's next. You will notice that you can enter any number of newlines (or tabs or spaces) and scanf will still wait for more.
However, when you enter the second string, the sequence of whitespace is delimited and scanning stops.
以上這篇C語(yǔ)言中scanf函數(shù)與空格回車的用法說(shuō)明就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C++實(shí)現(xiàn)寢室衛(wèi)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)寢室衛(wèi)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C++實(shí)現(xiàn)LeetCode(57.插入?yún)^(qū)間)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(57.插入?yún)^(qū)間),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C/C++實(shí)現(xiàn)貪吃蛇逐步運(yùn)動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了C/C++實(shí)現(xiàn)貪吃蛇逐步運(yùn)動(dòng)效果的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05C/C++?Qt數(shù)據(jù)庫(kù)與SqlTableModel組件應(yīng)用教程
SqlTableModel?組件可以將數(shù)據(jù)庫(kù)中的特定字段動(dòng)態(tài)顯示在TableView表格組件中,這篇文章將主要介紹SqlTableModel組件一些常用的操作,需要的朋友可以參考一下2021-12-12C語(yǔ)言實(shí)現(xiàn)折半查找法(二分法)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)折半查找法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11C語(yǔ)言實(shí)現(xiàn)支持動(dòng)態(tài)拓展和銷毀的線程池
這篇文章主要為大家介紹了C語(yǔ)言實(shí)現(xiàn)支持動(dòng)態(tài)拓展和銷毀的線程池,感興趣的小伙伴們可以參考一下2016-01-01