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