getchar、scanf以及缓冲区的概念
????? getch()和getche()是conio.h中的庫(kù)函數(shù),它的作用是從鍵盤接收字符,getchar帶有回顯。
????? 與前面兩個(gè)函數(shù)的區(qū)別在于: getchar()函數(shù)等待輸入直到按回車才結(jié)束(前提是緩沖區(qū)沒有數(shù)據(jù)),回車前的所有輸入字符都會(huì)逐個(gè)顯示在屏幕上。但只有第一個(gè)字符作為函數(shù)的返回值。 #include "stdio.h" #include "stdlib.h" int main(void) {char c;while((c=getchar())!='\n') //每個(gè)getchar()依次讀入一個(gè)字符printf("%c",c); //按照原樣輸出printf("\n");system("pause");return 0; }?????? 程序運(yùn)行時(shí),首先停下來(lái),等你輸入一串字符串,輸入完畢后,它把你輸入的整個(gè)字符串都輸出來(lái)了,咦,你不是說(shuō)getchar()只返回第一個(gè)字符么,這里怎么?
????? 因?yàn)槲覀冚斎氲淖址⒉皇侨×说谝粋€(gè)字符就把剩下的字符串丟掉了,它還在我們的內(nèi)存中,好比,開閘放水,我們把水放到閘里去以后,開一次閘就放掉一點(diǎn),開一次就放掉一點(diǎn),直到放光了為止,這里開閘動(dòng)作就相當(dāng)于調(diào)用一次getchar()。我們輸入的字符串也是這么一回事,首先我們輸入的字符串是放在內(nèi)存的緩沖區(qū)中的,我們調(diào)用一次getchar()就把緩沖區(qū)中里出口最近的一個(gè)字符輸出,也就是最前面的一個(gè)字符輸出,輸出后,就把它釋放掉了,但后面還有字符串,所以我們就用循環(huán)把最前面的一個(gè)字符一個(gè)個(gè)的在內(nèi)存中釋放掉,直到滿足循環(huán)條件退出為止。
???? 例子中循環(huán)條件里的'\n '實(shí)際上就是你輸入字符串后的回車符,所以意思就是說(shuō),直到遇到回車符才結(jié)束循環(huán),而getchar()函數(shù)就是等待輸入(或緩沖區(qū)中的數(shù)據(jù))直到按回車才結(jié)束,所以實(shí)現(xiàn)了整個(gè)字符串的輸出。當(dāng)然,我們也可以把循環(huán)條件改一下,比如while ((c=getchar())!='a'),什么意思呢,意思就是遇到字符'a'就停止循環(huán),當(dāng)然意思是如果你輸入“12345a213123 ”那么只會(huì)輸出到a前面的那個(gè)字符,結(jié)果是12345。
???? 再次注意:用getchar()它是從“流”中間去讀取,所以第一個(gè)getchar()接受的是剛剛中斷的流隊(duì)列中即將出列的第一個(gè)字符(不限于回車符,上面舉過(guò)例子了),如果流隊(duì)列不為空,執(zhí)行g(shù)etchar()就繼續(xù)放水,直到把回車符也放空為止,空了之后再在執(zhí)行g(shù)etchar()就停下等待你的輸入了;我們用getch()為什么每次都是等待用戶的輸入呢?因?yàn)間etch()是從鍵盤接收,即時(shí)的接收,并不是從stdin流中去讀取數(shù)據(jù)。
???? 下面是我的討論:
???? 先來(lái)一段code:
#include "stdio.h" #include "stdlib.h" int main(void) {char c;for(;(c=getchar())!='a';)printf("%c",c);getchar();c=getchar();printf("%c",c);system("pause");return 0; }輸入:??ssss回車
得到:???ssss
?????????? 光標(biāo)處(等待輸入)
說(shuō)明:由于一直沒有輸入字符a,所以此時(shí)程序沒有結(jié)束,進(jìn)入到for循環(huán)后一直沒有退出。鍵入回車后,運(yùn)行c=getchar(),依次從緩沖區(qū)內(nèi)取出(for循環(huán)):'s''s''s''s'' ' 包括回車的換行符,并將其全部打印了出來(lái)。。
如果我們輸入:ssssa回車
得到:ssss光標(biāo)處(等待輸入)
說(shuō)明:程序讀入到字符a的時(shí)候跳出了for循環(huán),但是由于我們用getchar();清除了換行符'\n ',后面第7句c=getchar();需要你輸入一個(gè)字符(因?yàn)閟sssa后面并沒有新的字符),所以程序仍然沒有結(jié)束。如果我們注釋掉getchar();這一句,那么c=getchar();這行代碼就可以讀取ssssa后面的回車符號(hào)了,就可以得到這樣的輸出:??
????? ?ssss
?????? 光標(biāo)處(程序結(jié)束)
這個(gè)輸入ssssa中的回車中的換行符'\n '就被c=getchar();這一句讀取并輸出了。
??????? 總結(jié):
?????? 鍵盤輸入的字符都存到緩沖區(qū)內(nèi),一旦鍵入回車,getchar就進(jìn)入緩沖區(qū)讀取字符,一次只返回第一個(gè)字符作為getchar函數(shù)的值,如果有循環(huán)或足夠多的getchar語(yǔ)句,就會(huì)依次讀出緩沖區(qū)內(nèi)的所有字符直到'\n '。要理解這一點(diǎn),之所以你輸入的一系列字符被依次讀出來(lái),是因?yàn)檠h(huán)的作用使得反復(fù)利用getchar在緩沖區(qū)里讀取字符,而不是getchar可以讀取多個(gè)字符,事實(shí)上getchar每次只能讀取一個(gè)字符。如果需要取消' \n'的影響,可以用getchar();來(lái)清除,這里getchar();只是取得了'\n '但是并沒有賦給任何字符變量,所以不會(huì)有影響,相當(dāng)于清除了這個(gè)字符,還要注意的是這里你在鍵盤上輸入ssss看到的回顯正是來(lái)自于getchar的作用,如果用getch就看不到你輸入了什么。
????????? 2、scanf
????? scanf這個(gè)庫(kù)函數(shù)比較奇怪,而且存在一定的缺陷,所以很多人都不用了,這里還是要簡(jiǎn)單介紹一下。
????? scanf輸入字符串、整型、實(shí)型等數(shù)據(jù)判斷的方式都一樣,回車、空格、tab鍵都認(rèn)為是一個(gè)數(shù)據(jù)的結(jié)束,當(dāng)然字符的話,一個(gè)字符就是結(jié)束了。回車、空格等都有對(duì)應(yīng)的ASCII碼,所以用scanf輸入字符時(shí)要小心這些東西被當(dāng)成字符輸進(jìn)去,而輸入字符串和整型、實(shí)型等數(shù)據(jù)時(shí)這些都被當(dāng)成分隔符而不會(huì)被輸入到字符數(shù)組或變量里。當(dāng)然如果輸入格式不是"%s%s"而是"%s,%s"分隔符就是逗號(hào)了。
???? 說(shuō)了這么多舉幾個(gè)例子:
輸入:
hello回車
world回車
得到如下的輸出:
n1=hello,n2=wolrd光標(biāo)處(程序結(jié)束)
?????? 這里hello后面就是輸入再多個(gè)回車、空格也不會(huì)被賦值到n2中的,因?yàn)槭褂胹canf函數(shù)輸入字符串的時(shí)候他們只是被當(dāng)做分隔符。另外就是輸入n2的時(shí)候,n2后面的那個(gè)回車也被當(dāng)做了分隔符,所以輸出的時(shí)候,只是簡(jiǎn)單的輸出了n1和n2的內(nèi)容,而沒有輸出回車換行符。
如果輸入:
hello回車
光標(biāo)處(等待輸入)
說(shuō)明回車被認(rèn)成分隔符,所以程序還要你輸入一個(gè)字符串來(lái)賦給n2。
其實(shí)這時(shí)緩沖區(qū)里是有一個(gè)'\n '被留下來(lái)的,程序改成這樣:
#include "stdio.h" int main(void) {char n1[10]; char n2[10];char n3,n4; scanf("%s",n1); scanf("%s",n2); printf("n1=%s,n2=%s",n1,n2);n3=getchar(); //n3讀取了n2后面的那個(gè)回車字符并輸出printf("%c",n3);//n4=getchar();//printf("%c",n4); return 0; }輸入:
hello回車
world回車
得到:??
n1=hello,n2=wolrd
光標(biāo)處(程序結(jié)束)
如果取消最后兩行的注釋,同樣的輸入得到:
?n1=hello,n2=wolrd
光標(biāo)處(等待輸入)
說(shuō)明此時(shí)緩沖區(qū)內(nèi)只有一個(gè)'\n ',第二個(gè)getchar就需要你再輸入一個(gè)字符了,緩沖區(qū)內(nèi)已經(jīng)沒有字符了。
?? scanf不會(huì)把回車、空格賦給字符串但是會(huì)賦給字符,就如同getchar一樣,這時(shí)就要考慮'\n '的存在了。
比如:
輸入:
hello回車
得到:
n1=hello,n2=10光標(biāo)處(程序結(jié)束)?? ?//10是'\n '的ASCII碼.
如果輸入:
hello 空格回車(一定要有回車,因?yàn)閟canf也是要等回車,準(zhǔn)確說(shuō)是' \n'才會(huì)去讀緩沖區(qū)的。)
得到:
n1=hello,n2=32光標(biāo)處(程序結(jié)束) ???//32是空格的ASCII碼。
再羅嗦一下,如果最后一句輸出n2=%d改成n2=%c,則輸入:
hello回車
得到:
n1=hello,n2=
光標(biāo)處(程序結(jié)束)
是不是和getchar一樣可以把'\n '讀出來(lái)呢,呵呵。
總結(jié)一下就是:
如果scanf輸入的不是字符,那么分隔符為回車,空格、tab鍵時(shí),兩個(gè)數(shù)據(jù)之間的分隔符只是起區(qū)別兩個(gè)數(shù)據(jù)的作用,把分隔好的兩個(gè)數(shù)據(jù)分別賦值到各自定義好的變量或數(shù)組中去,兩個(gè)數(shù)據(jù)之間的分隔符被從緩沖區(qū)讀出但是不起任何作用,當(dāng)然最后一個(gè)'\n '會(huì)被留在緩沖區(qū)內(nèi),除非用getchar();或scanf("%c",&c);把它讀出來(lái)。
回車是一定要有的,不管getchar還是scanf只要是通過(guò)緩沖區(qū)輸入數(shù)據(jù)的函數(shù)都是等待回車鍵'\n '出現(xiàn)才進(jìn)入緩沖區(qū)的。再來(lái)個(gè)整型數(shù)據(jù)、字符串、字符的混合例子:
#include "stdio.h" int main(void) {int a,b,c;char n1[10];char n2,n3;scanf("%d%d",&a,&b);scanf("%c",&n2);scanf("%d",&c);scanf("%s",n1);scanf("%c",&n3);printf("a=%d,b=%d,n2=%c,c=%d,n1=%s,n3=%c",a,b,n2,c,n1,n3);return 0; }輸入:
12(若干空格或回車都不影響結(jié)果,這里用了回車)
34(這里還要求輸入,因?yàn)閟canf只得到了一個(gè)整型數(shù)據(jù),而緩沖區(qū)內(nèi)沒有整型數(shù)據(jù)了。要有回車或空格表示這個(gè)數(shù)據(jù)結(jié)束了,留下來(lái)的空格或回車被下個(gè)%c接受,這里用了回車,可以試一下空格)
45 jfdkjfa(回車)
得到:
a=12,b=34,n2=
,c=45,n1=jfdkjfa,n3=
光標(biāo)處(程序結(jié)束)
?????? 這里說(shuō)明一下過(guò)程:在前兩個(gè)整型數(shù)據(jù)輸入時(shí),兩個(gè)數(shù)據(jù)之間無(wú)論是回車還是若干空格都被scanf當(dāng)做分隔符,好了,scanf讀到分隔符(回車或空格)時(shí),把第一個(gè)整型數(shù)據(jù)送到變量a中,緩沖區(qū)中留下分隔符和下面的整型數(shù)據(jù),這時(shí)scanf再讀當(dāng)然先讀分隔符,但是要求輸入的還是整型數(shù)據(jù)(%d),所以分隔符被忽略,如果這時(shí)要求輸入字符%c(不是字符串%s),那么分隔符將以一個(gè)字節(jié)的形式送到字符變量里,就如同這里的n2。同理可以知道c和n1的保存過(guò)程,最后的n3正是接收了輸入時(shí)的最后一個(gè)回車。
好了如果看到這里你都理解了那么看最后一個(gè)例子:
輸入:
95回車
得到:
95,
光標(biāo)處(程序結(jié)束)
很明顯這是由于分隔符(回車)被getchar讀取并輸出了,如果加入一句:getchar();
#include "stdio.h" int main(void) {int a;char ch;scanf("%d",&a);getchar();ch=getchar();printf("%d,%c",a,ch);return 0; }輸入:
95回車
c回車
得到:
95,c光標(biāo)處(程序結(jié)束)
總結(jié)
以上是生活随笔為你收集整理的getchar、scanf以及缓冲区的概念的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 程序员面试100题之十二:求数组中最长递
- 下一篇: 不用比较运算符及循环控制语句,判断int