| 分類(lèi):C++教學(xué) |
你肯定會(huì )奇怪為什么一開(kāi)始先說(shuō)這個(gè),一開(kāi)始不都是數據類(lèi)型什么的嘛,這個(gè)寫(xiě)在最前面因為后面的程序即使最簡(jiǎn)單的code都會(huì )用到輸入輸出,輸出比較簡(jiǎn)單,可以放在后面再說(shuō),但是輸入就不同了,如果不先了解一下,可能會(huì )得到和你預想不同的結果哦^_^.也正是由于和一般的c語(yǔ)言介紹方式不同,為了看起來(lái)正規一些,我就把這章叫做chapter0了,完全可以先跳過(guò)去,直接看chapter1.
1.getchar
先引用一下前人的成果(有修改)^_^:http://blog.csdn.net/cxyol/archive/2006/03/18/628324.aspx
getchar()是stdio.h中的庫函數,它的作用是從stdin流中讀入一個(gè)字符,也就是說(shuō),如果stdin有數據的話(huà)不用輸入它就可以直接讀取了。而getch()和getche()是conio.h中的庫函數,它的作用是從鍵盤(pán)接收字符。getchar帶有顯示。
#include<stdio.h>
#include<conio.h>
void main()
{
}
這個(gè)程序你運行一下,相信你又會(huì )有疑問(wèn)了。這個(gè)就是從緩沖區中讀取了例子。第一次getchar()時(shí),確實(shí)需要人工的輸入,但是如果你輸了多個(gè)字符,以后的getchar()再執行時(shí)就會(huì )直接從緩沖區中讀取了。
#include<stdio.h>
#include<conio.h>
void main()
{
}
程序運行時(shí),首先停下來(lái),等你輸入一串字符串,輸入完畢后,它把你輸入的整個(gè)字符串都輸出來(lái)了,咦,你不是說(shuō)getchar()只返回第一個(gè)字符么,這里怎么?
因為我們輸入的字符串并不是取了第一個(gè)字符就把剩下的字符串丟掉了,它還在我們的內存中,就好比,開(kāi)閘放水,我們把水放到閘里去以后,開(kāi)一次閘就放掉一點(diǎn),開(kāi)一次就放掉一點(diǎn),直到放光了為止,這里開(kāi)閘動(dòng)作就相當于調用一次getchar()。我們輸入的字符串也是這么一回事,首先我們輸入的字符串是放在內存的緩沖區中的,我們調用一次getchar()就把緩沖區中里出口最近的一個(gè)字符輸出,也就是最前面的一個(gè)字符輸出,輸出后,就把它釋放掉了,但后面還有字符串,所以我們就用循環(huán)把最前面的一個(gè)字符一個(gè)個(gè)的在內存中釋放掉,直到不滿(mǎn)足循環(huán)條件退出為止。
例子中循環(huán)條件里的'\n'實(shí)際上就是你輸入字符串后的回車(chē)符,所以意思就是說(shuō),直到遇到回車(chē)符才結束循環(huán),而getchar()函數就是等待輸入(或緩沖區中的數據)直到按回車(chē)才結束,所以實(shí)現了整個(gè)字符串的輸出。當然,我們也可以把循環(huán)條件改一下,比如while ((c=getchar())!='a'),什么意思呢,意思就是遇到字符'a'就停止循環(huán),當然意思是如果你輸入“12345a213123\n”那么只會(huì )輸出到a,結果是12345a。
再次注意:用getchar()它是從“流”中間去讀取,所以第一個(gè)getchar()接受的是剛剛中斷的流隊列中即將出列的第一個(gè)字符(不限于回車(chē)符,上面舉過(guò)例子了),如果流隊列不為空,執行g(shù)etchar()就繼續放水,直到把回車(chē)符也放空為止,空了之后再在執行g(shù)etchar()就停下等待你的輸入了;我們用getch()為什么每次都是等待用戶(hù)的輸入呢?因為getch()是從鍵盤(pán)接收,即時(shí)的接收,并不是從stdin流中去讀取數據。
3.如何清空輸入緩沖區的內容?
char sbuf[1024];
// ...
fgets( sbuf, 1024, stdin );
// ...
在windows 的vc下面就可以這樣了:
for(int i=0;i<10;++i)
{
}
這里說(shuō)到gcc編譯器沒(méi)有定義fflush的實(shí)現,我們一般用getchar();來(lái)清除緩沖區.
下面是我的討論:
先來(lái)一段code:
#include <stdio.h>
main()
{
}
輸入:
ssss回車(chē)
得到:
ssss
光標處(等待輸入)
說(shuō)明:此時(shí)程序沒(méi)有結束,進(jìn)行到for循環(huán),因為并沒(méi)有字符a出現,所以還沒(méi)跳出for循環(huán).鍵入回車(chē)后,getchar
依次從緩沖區內取出(for循環(huán)):'s''s''s''s''\n'
如果我們輸入:
ssssa回車(chē)
得到:
ssss光標處(等待輸入)
說(shuō)明:程序已經(jīng)跳出for循環(huán),但是由于我們用getchar();清除了換行'\n',后面第7句c=getchar();需要你輸入一個(gè)字符(因為ssssa后面并沒(méi)有新的字符),所以程序仍然沒(méi)有結束.如果我們注釋掉getchar();這一句,那么得到:
ssss
光標處(程序結束)
這個(gè)輸入ssssa是的回車(chē)中的換行符'\n'就被c=getchar();這一句讀取并輸出了。
總結:
鍵盤(pán)輸入的字符都存到緩沖區內,一旦鍵入回車(chē),getchar就進(jìn)入緩沖區讀取字符,一次只返回第一個(gè)字符作為getchar函數的值,如果有循環(huán)或足夠多的getchar語(yǔ)句,就會(huì )依次讀出緩沖區內的所有字符直到'\n'.要理解這一點(diǎn),之所以你輸入的一系列字符被依次讀出來(lái),是因為循環(huán)的作用使得反復利用getchar在緩沖區里讀取字符,而不是getchar可以讀取多個(gè)字符,事實(shí)上getchar每次只能讀取一個(gè)字符.如果需要取消'\n'的影響,可以用getchar();來(lái)清除,這里getchar();只是取得了'\n'但是并沒(méi)有賦給任何字符變量,所以不會(huì )有影響,相當于清除了這個(gè)字符.還要注意的是這里你在鍵盤(pán)上輸入ssss看到的回顯正是來(lái)自于getchar的作用,如果用getch就看不到你輸入了什么.再引一篇文章:
http://www.cnblogs.com/biser/archive/2004/09/23/45704.aspx
1.機理
你鍵盤(pán)輸入了東西,而此時(shí)你又沒(méi)有用程序去getchar她,請問(wèn)這個(gè)時(shí)候你按的鍵的狀態(tài)保存在何處?為什么你一會(huì )兒去getchar的時(shí)候能得到呢
(例子好舉,你先做一個(gè)1分鐘延遲,然后再getchar,會(huì )發(fā)現一分鐘前按的東西會(huì )顯示出來(lái))
實(shí)際上是輸入設備->內存緩沖區->程序getchar
你按的鍵是放進(jìn)緩沖區了,然后供程序getchar
你有沒(méi)有試過(guò)按住很多鍵然后等一會(huì )兒會(huì )滴滴滴滴響,就是緩沖區滿(mǎn)了,你后頭按的鍵沒(méi)有存進(jìn)緩沖區.
2.getchar()和getch()
然后就可以給你講了
getchar是回車(chē)以后才進(jìn)緩沖區
getch是每次都進(jìn)緩沖區
用你的程序來(lái)說(shuō)(我怎么覺(jué)得應該是\n不是/n)
其實(shí)你輸入computer,沒(méi)按回車(chē)之前, 運行都停止在
getchar()里頭,根本沒(méi)有進(jìn)入循環(huán),自然也沒(méi)有運行printf
當你一按回車(chē),才從getchar出來(lái),然后以后因為鍵盤(pán)緩沖區里頭有東西,就一個(gè)一個(gè)字符getchar出來(lái)了
想立刻回顯,用getch就好了
2.scanf
scanf這個(gè)庫函數比較奇怪,而且存在一定的缺陷,所以很多人都不用了,這里還是要簡(jiǎn)單介紹一下.
scanf輸入字符串,整型,實(shí)型等數據判斷的方式都一樣,回車(chē),空格,tab鍵都認為是一個(gè)數據的結束,當然字符的話(huà),一個(gè)字符就是結束了,回車(chē),空格等都有對應的ascii碼,所以用scanf輸入字符時(shí)要小心這些東東被當成字符輸進(jìn)去,而輸入字符串和整型,實(shí)型等數據時(shí)這些都被當成分隔符而不會(huì )被輸入到字符數組或變量里.當然如果輸入格式不是"%s%s"而是"%s,%s"分隔符就是逗號了,這個(gè)講到輸入輸出函數時(shí)再說(shuō).
說(shuō)了這么多舉幾個(gè)例子:
#include <stdio.h>
int main()
{
char n1[10];
char n2[10];
scanf("%s",n1);
scanf("%s",n2);
printf("n1=%s,n2=%s",n1,n2);
}
輸入:
hello回車(chē)
world回車(chē)
得到:
n1=hello,n2=wolrd光標處(程序結束)
這里hello后面就是輸入再多個(gè)回車(chē),空格也不會(huì )被賦值到n2中的,因為他們只是分隔符.
如果輸入:
hello回車(chē)
光標處(等待輸入)
說(shuō)明回車(chē)被認成分隔符,所以程序還要你輸入一個(gè)字符串來(lái)賦給n2.
其實(shí)這時(shí)緩沖區里是有一個(gè)'\n'被留下來(lái)的,程序改成這樣:
#include <stdio.h>
int main()
{
char n1[10];
char n2[10];
char n3,n4;
scanf("%s",n1);
scanf("%s",n2);
printf("n1=%s,n2=%s",n1,n2);
n3=getchar();
printf("%c",n3);
//n4=getchar();
//printf("%c",n4);
}
輸入:
hello回車(chē)
world回車(chē)
得到:
hello
world
n1=hello,n2=wolrd
光標處(程序結束)
如果取消最后兩行的注釋,同樣的輸入得到:
hello
world
n1=hello,n2=wolrd
光標處(等待輸入)
說(shuō)明此時(shí)緩沖區內只有一個(gè)'\n',第二個(gè)getchar就需要你再輸入一個(gè)字符了,緩沖區內已經(jīng)沒(méi)有字符了.
scanf不會(huì )把回車(chē)空格賦給字符串但是會(huì )賦給字符,就如同getchar一樣,這時(shí)就要考慮'\n'的存在了.
比如:
#include <stdio.h>
int main()
{
char n1[10];
char n2;
scanf("%s",n1);
scanf("%c",&n2);
printf("n1=%s,n2=%d",n1,n2);
}
輸入:
hello回車(chē)
得到:
n1=hello,n2=10光標處(程序結束) //10是'\n'的ascii碼.
如果輸入:
hello 空格回車(chē)(一定要有回車(chē),因為scanf也是要等回車(chē),準確說(shuō)是'\r'才會(huì )去讀緩沖區的.)
得到:
n1=hello,n2=32光標處(程序結束) //32是空格的ascii碼.
再羅嗦一下,如果最后一句輸入n2=%d改成n2=%c,則輸入:
hello回車(chē)
得到:
n1=hello,n2=
光標處(程序結束)
是不是和getchar一樣可以把'\n'讀出來(lái)呢,呵呵.
總結一下就是:
如果scanf輸入的不是字符,那么分隔符為回車(chē),空格,tab鍵時(shí),兩個(gè)數據之間的分隔符只是起區別兩個(gè)數據的作用,把分隔好的兩個(gè)數據分別賦值到各自定義好的變量或數組中去,兩個(gè)數據之間的分隔符被從緩沖區讀出但是不起任何作用,當然最后一個(gè)'\n'會(huì )被留在緩沖區內,除非用getchar();或scanf("%c",&c);把它讀出來(lái).
回車(chē)是一定要有的,不管getchar還是scanf只要是通過(guò)緩沖區輸入數據的函數都是等待回車(chē)鍵'\r'出現才進(jìn)入緩沖區的.再來(lái)個(gè)整型數據,字符串,字符的混合例子:
#include <stdio.h>
int main()
{
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);
}
輸入:
12(若干空格或回車(chē)就不影響結果,這里用了回車(chē))
34(這里還要求輸入,因為scanf只得到了一個(gè)整型數據,而緩沖區內沒(méi)有整型數據了。要有回車(chē)或空格表示這個(gè)數據結束了,留下來(lái)的空格或回車(chē)被下個(gè)%c接受,這里用了回車(chē),可以試一下空格)
45 jfdkjfa(回車(chē))
得到:
a=12,b=34,n2=
,c=45,n1=jfdkjfa,n3=
光標處(程序結束)
這里說(shuō)明一下過(guò)程:在前兩個(gè)整型數據輸入時(shí),兩個(gè)數據之間無(wú)論是回車(chē)還是若干空格都被scanf當做分隔符,好了,scanf讀到分隔符(回車(chē)或空格)時(shí),把第一個(gè)整型數據送到變量a中,緩沖區中留下分隔符和下面的整型數據,這時(shí)scanf再讀當然先讀分隔符,但是要求輸入的還是整型數據(%d),所以分隔符被忽略,如果這時(shí)要求輸入字符%c(不是字符串%s),那么分隔符將以一個(gè)字節的形式送到字符變量里,就如同這里的n2.同理可以知道c和n1的保存過(guò)程,最后的n3正是接收了輸入時(shí)的最后一個(gè)回車(chē).
好了如果看到這里你都理解了那么看最后一個(gè)例子:
#include <stdio.h>
main(){
int a;
char ch;
scanf("%d",&a);
ch=getchar();
printf("%d,%c",a,ch);
}
輸入:
95回車(chē)
得到:
95,
光標處(程序結束)
很明顯這是由于分隔符(回車(chē))被getchar讀取并輸出了,如果加入一句:getchar();
#include <stdio.h>
main(){
int a;
char ch;
scanf("%d",&a);
getchar();
ch=getchar();
printf("%d,%c",a,ch);
}
輸入:
95回車(chē)
c回車(chē)
得到:
95,c光標處(程序結束)
聯(lián)系客服