區(qū)分C語言中getch、getche、fgetc、getc、getchar、fgets、gets函數(shù)
首先,這兩個函數(shù)不是C標準庫中的函數(shù): int getch(void) //從標準輸入讀入一個字符,當你用鍵盤輸入的時候,屏幕不顯示你所輸入的字符。也就是,不帶回顯。 int getche(void) //從標準輸入讀入一個字符,鍵盤輸入的時候,屏幕顯示所輸入的字符。帶回顯。 這兩個函數(shù)都不帶緩沖區(qū),其包含在頭文件為conio.h ,需要記住的是conio.h不是C標準庫中的頭文件。Micorsoft 和 Borland的 C編譯器提供了conio.h,用來創(chuàng)建控制臺文本用戶界面。一般在Windows系統(tǒng)下安裝了VS、VC等,就可以包含conio.h頭文件。但是一般在Unix、Linux系統(tǒng)中,/usr/include/中都沒有這個頭文件。 getch和getche在等待用戶從鍵盤輸入的時候,用戶按下一個鍵后,不需要按回車,程序自動往下執(zhí)行。在Linux中,終端輸入在缺省情況下是被“一鍋端”的,也就是說整行輸入是被一起處理的。通常,這是一種人們所希望的方便的辦法,但它也意味著在讀入數(shù)據(jù)時必須按一下回車鍵表示輸入行結束后才能得到輸入的數(shù)據(jù)。在游戲中,很多都提供了“老板鍵”,它的實現(xiàn),就是利用了這兩個函數(shù)。 其次,除了getch和getche,其他的都是C標準庫中的頭文件,包含在頭文件stdio.h中。 int fgetc ( FILE * stream ); //從流stream中讀一個字符。可以將標準輸入stdin作為它的實參,這時候從標準輸入讀取一個字符。 int getc(FILE * stream); //和fgetc等效,由fgetc通過宏實現(xiàn)。 int getchar ( void ); //getchar() 函數(shù)等待輸入直到按回車 才結束(前提是緩沖區(qū)沒有數(shù)據(jù)),回車前的 所有輸入字符都會逐個顯 //示在屏幕上。但每次調用只讀入 最開始的一個字符并將其作為函數(shù)的返回值 。 說明:getc、getchar都是通過宏定義借助fgetc實現(xiàn)。如getchar的實現(xiàn)為,#define getchar() fgetc(stdin)。對于getchar函數(shù),因為我們輸入的字符串并不是取了第一個字符就把剩下的字符串丟掉了 ,它還在我們的內存中,就好比,開閘放水,我們把水放到閘里去以后,開一次閘就放掉一點,開一次就放掉一點,直到放光了為止,這里開閘動作就相當于調用一次 getchar() 。我們輸入的字符串也是這么一回事,首先我們 輸入的字符串是放在內存的緩沖區(qū) 中的,我們調用一次 getchar() 就把緩沖區(qū)中里出口最近的一個字符輸出,也就是最前面的一個字符輸出,輸出后,就把它釋放掉了,但后面還有字符串,所以我們就用循環(huán)把最前面的一個字符一個個的在內存中釋放掉,直到最后把回車符也放空為止,空了之后再在執(zhí)行 getchar() 就停下等待你的輸入了。 注意: 1.在windows環(huán)境下,按鍵盤上的回車產(chǎn)生了 2 個字符 : 回車符 ('\r') 和換行符 ('\n') ?;剀嚪?'\r'(CR:carriage return: 倒車)使光標回到這行的首部,換行符 ('\n')(new line) 然后再換行。但是在linux環(huán)境下,按鍵盤上的回車只產(chǎn)生一個字符'\n' 2.如何清空輸入緩沖區(qū)的內容? 如果我想讓 getchar() 每次都能夠等待用戶輸入的話就要清空緩沖區(qū),下面就介紹方法(不同平臺) C 標準規(guī)定 fflush() 函數(shù)是用來刷新輸出( stdout )緩存的。對于輸入( stdin ),它是沒有定義的。 但是有些編譯器也定義了 fflush(stdin ) 的實現(xiàn),比如微軟的 VC 。其它編譯器是否也定義了 fflush(stdin) 的實現(xiàn)應當查找它的手冊。 GCC 編譯器沒有定義它的實現(xiàn),所以不能使用 fflush(stdin) 來刷新輸入緩存。 對于沒有定義 fflush(stdin) 的編譯器,可以 使用 fgets() 函數(shù)來刷新輸入緩存 (比用 getchar() 、 scanf() 等函數(shù)通用性好)??梢赃@樣忽略輸入流中留下的回車等其它輸入,從而使下一次的輸入總保持一個 “ 干凈 ” 的狀態(tài)。(這個是任何平臺下都可以的) 在 windows 的 vc 下面就可以這樣了: for(int i=0;i<10;++i) { char ch=getchar(); fflush(stdin); // 每次都會有等待狀態(tài)了 }
fgets()用來從參數(shù)stream所指的文件內讀入字符并存到參數(shù)s所指的內存空間,直到出現(xiàn)換行字符,讀到文件尾或是已讀了size-1個字符為止,最后會加上NULL作為字符串結束。gets()若成功則返回s指針,返回NULL則表示有錯誤發(fā)生。 char * fgets (char * str, int num, FILE *stream); //從流stream中讀入最多num個字符到字符數(shù)組str中,當遇到換行符時、或讀到num-1個字符時停止。 //讀入的字符串中最后包含讀到的換行符, 自動加上'\0'空字符結尾 char * gets ( char * str ); //從標準輸入stdin讀取一個字符串,遇到換行或結束時候終止。 //不同于fgets,他沒有指定num,所以需要注意字符數(shù)組str的大小。 //讀入字符不包括最后的換行符,但自動加上'\0'空字符結尾 說明: fgets和gets之間沒有宏定義的關系,彼此各自有自己的實現(xiàn)。蠕蟲病毒的實現(xiàn)就是函數(shù)gets的“功勞”。gets函數(shù)的任務是從流中讀入一個字符串。它的調用者會告訴它把讀入的字符串放在什么地方。但是,gets()函數(shù)并不檢查緩沖區(qū)大小 ,如果調用者提供了一個指向堆棧的指針,并且get()函數(shù)讀入的字符數(shù)量超過了超過了緩沖區(qū)的空間大小,get()會愉快地將多出來的字符繼續(xù)寫入到堆棧中,這就覆蓋了堆棧中原來的內容。如: main() { char line[512]; //在程序的堆棧上分配512個字符的空間 ... gets(line); //蠕蟲病毒的入口,可以將惡意代碼通過多出來的數(shù)據(jù)寫入堆棧 } 建議不要用getch和getche,因為它們不是C標準庫中的函數(shù)。用它們寫出的程序可移植性差,不同的編譯器不保證可以包含conio.h,其他的函數(shù)都是對流操作,都有相關緩沖區(qū),此外建議用fgets函數(shù)徹底替代gets函數(shù)。 另外,絕大多數(shù)的這些get函數(shù),都有對應的put版本。 int fputc ( int character, FILE * stream ); int putc ( int character, FILE * stream ); //通過宏定義和fputc實現(xiàn) int putchar ( int character ); //通過宏定義實現(xiàn):#define putchar(c) fputc(c, stdout) int fputs ( const char * str, FILE * stream ); int puts ( const char * str ); 說明:兩者之間無宏定義實現(xiàn)關系。puts(const char *str)近似等效于fputs(cosnt char *str, stdout),不同點是前者還輸出一個'\n' 最后,關于EOF EOF是在stdio.h文件中定義的符號常量,值為-1。 如: fputc函數(shù)返回一個值:如果輸出成功則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF。 fgetc函數(shù)讀字符時遇到文件結束符,函數(shù)返回一個文件結束標記EOF。如果想從一個磁盤文件順序讀入字符并在屏幕上顯示,可以: ch = fgetc(fp); while(ch != EOF){ putchar(ch); ch = fgetc(fp); } 注意,EOF不是可輸出字符,因此不能在屏幕上顯示。由于ASCII碼不可能出現(xiàn)-1,因此EOF定義為-1是合適的。 當讀入的字符值等于-1(即 EOF)時,表示讀入的已不是正常的字符,而是文件結束符。但以上只適用于讀取文本文件的情況?,F(xiàn)在ANSI C 已經(jīng)允許用緩沖文件系統(tǒng)處理二進制文件,而讀入某一個字節(jié)中的二進制數(shù)據(jù)的值有可能是-1,而這又恰好是EOF的值。這就出現(xiàn)了需要讀入有用數(shù)據(jù),卻處理為“文件結束”。feof(fp) 用來測試fp所指向的文件當前狀態(tài)是否是“文件結束” 。如果想順序讀入一個二進制文件數(shù)據(jù),可以: while(!feof(fp)){ c = fgetc(fp); ... } 詳情請查閱C標準庫。 |
|