C語言超詳細(xì)講解getchar函數(shù)的使用
一、getchar 函數(shù)
從上面的介紹來看,我們要正確使用getchar函數(shù),首先得了解什么是緩沖區(qū)。
二、緩沖區(qū)
1、什么是緩沖區(qū)
緩沖區(qū)又稱為緩存,它是內(nèi)存空間的一部分。
也就是說,在內(nèi)存空間中預(yù)留了一定的存儲(chǔ)空間,這些存儲(chǔ)空間用來緩沖輸入或輸出的數(shù)據(jù),這部分預(yù)留的空間就叫做緩沖區(qū)。
緩沖區(qū)根據(jù)其對應(yīng)的是輸入設(shè)備輸出設(shè)備,分為輸入緩沖區(qū)和輸出緩沖區(qū)。
2、為什么要存在緩沖區(qū)
我們?yōu)槭裁匆刖彌_區(qū)呢?
比如我們從磁盤里取信息,我們先把讀出的數(shù)據(jù)放在緩沖區(qū),計(jì)算機(jī)再直接從緩沖區(qū)中取數(shù)據(jù),等緩沖區(qū)的數(shù)據(jù)取完后再去磁盤中讀取,這樣就可以減少磁盤的讀寫次數(shù),再加上計(jì)算機(jī)對緩沖區(qū)的操作大大快于對磁盤的操作,故應(yīng)用緩沖區(qū)可大大提高計(jì)算機(jī)的運(yùn)行速度。
又比如,我們使用打印機(jī)打印文檔,由于打印機(jī)的打印速度相對較慢,我們先把文檔輸出到打印機(jī)相應(yīng)的緩沖區(qū),打印機(jī)再自行逐步打印,這時(shí)我們的CPU可以處理別的事情?,F(xiàn)在您基本明白了吧,緩沖區(qū)就是一塊內(nèi)存區(qū),它用在輸入輸出設(shè)備和CPU之間,用來緩存數(shù)據(jù)。它使得低速的輸入輸出設(shè)備和高速的CPU能夠協(xié)調(diào)工作,避免低速的輸入輸出設(shè)備占用CPU,解放出CPU,使其能夠高效率工作。
3、緩沖區(qū)的類型
緩沖區(qū)分為三種類型:全緩沖、行緩沖和不帶緩沖。
1、全緩沖
在這種情況下,當(dāng)填滿標(biāo)準(zhǔn)I/O緩存后才進(jìn)行實(shí)際I/O操作。全緩沖的典型代表是對磁盤文件的讀寫。
2、行緩沖
在這種情況下,當(dāng)在輸入和輸出中遇到換行符時(shí),執(zhí)行真正的I/O操作。這時(shí),我們輸入的字符先存放在緩沖區(qū),等按下回車鍵換行時(shí)才進(jìn)行實(shí)際的I/O操作。典型代表是鍵盤輸入數(shù)據(jù)。
3、不帶緩沖
也就是不進(jìn)行緩沖,標(biāo)準(zhǔn)出錯(cuò)情況stderr是典型代表,這使得出錯(cuò)信息可以直接盡快地顯示出來。
4、緩沖區(qū)的刷新
以下四種情況會(huì)引發(fā)緩沖區(qū)刷新:
- 緩沖區(qū)滿時(shí);
- 執(zhí)行 flush 語句;
- 執(zhí)行 endl 語句;
- 關(guān)閉文件。
三、getchar 函數(shù)的正確使用
1、getchar 的換行問題
我們來觀察下面這段代碼
#include<stdio.h> int main() { int ch = 0; while ((ch = (getchar())) != EOF) { putchar(ch); } return 0; }
我們可以看到我們每次從鍵盤輸入一個(gè)字符并回車后,putchar輸出時(shí)會(huì)自動(dòng)換行,就是因?yàn)槲覀兠看纬溯斎胱址?,還敲了一個(gè)回車,而這個(gè)回車會(huì)被存儲(chǔ)在緩沖區(qū)中,當(dāng)我們用getchar讀取字符時(shí),會(huì)從緩沖區(qū)中依次逐個(gè)讀取所有的字符(包括換行、空格、Tab),直到緩沖區(qū)中沒有數(shù)據(jù),每讀取一個(gè)字符就用putchar打印一下,所以這里會(huì)自動(dòng)換行。
^Z:Ctrl+Z,輸入后會(huì)被認(rèn)定為EOF,從而來結(jié)束循環(huán)(VS中有些時(shí)候要重復(fù)按三次才會(huì)結(jié)束循環(huán),其他編譯器都是按一次)。
2、getchar 與 scanf 的混合使用
我們來觀察下面這段代碼:
#include<stdio.h> int main() { char password[20] = { 0 }; printf("請輸入密碼:>"); scanf("%s", password); printf("請確認(rèn)密碼(Y/N):>"); int ch = getchar(); if (ch == 'Y') { printf("確認(rèn)成功\n"); } else { printf("確認(rèn)失敗\n"); } return 0; }
我們可以看到程序并沒有等待我們輸入Y/N來確認(rèn)密碼,而是直接結(jié)束,原因就是我們緩沖區(qū)中存放的是abcdef\n,而scanf函數(shù)是遇到空格、換行符(\n)、Tab時(shí)結(jié)束,所以\n并沒有被讀取走,而是繼續(xù)留在了緩沖區(qū)中,而當(dāng)getchar讀取數(shù)據(jù)時(shí)發(fā)現(xiàn)緩沖區(qū)中并不為空,所以直接讀取了\n,然后判斷if條件,結(jié)束程序,而不會(huì)等待我們輸入Y/N。
那么要如何避免這種情況發(fā)生呢?有兩種方法:
法一:在scanf后面加一個(gè)getchar(不推薦)
#include<stdio.h> int main() { char password[20] = { 0 }; printf("請輸入密碼:>"); scanf("%s", password); getchar(); //讀取剩下的\n printf("請確認(rèn)密碼(Y/N):>"); int ch = getchar(); if (ch == 'Y') { printf("確認(rèn)成功\n"); } else { printf("確認(rèn)失敗\n"); } return 0; }
我們在scanf函數(shù)后面加上一個(gè)getchar函數(shù),用于清空緩沖區(qū)里面多余的\n,但是這種方法有弊端,不推薦使用,具體弊端如下:
如圖:我們從鍵盤輸入abcd ef,我們可以看到,程序并沒有等待我們輸入Y/N,而是直接執(zhí)行if語句,這是因?yàn)?scanf函數(shù)遇到空格、換行符(\n)、Tab時(shí)會(huì)停止讀取,所以緩沖區(qū)中剩下的字符是_ef\n,一次getchar無法清空緩沖區(qū)。所以說,法一只能解決一部分情況,想要徹底解決scanf緩沖區(qū)殘留的問題需要用到法二。
法二:在scanf后面加 while( getchar() != ‘\n’) 語句(推薦)
#include<stdio.h> int main() { char password[20] = { 0 }; printf("請輸入密碼:>"); scanf("%s", password); getchar(); //讀取剩下的\n printf("請確認(rèn)密碼(Y/N):>"); while (getchar() != '\n') { ; } int ch = getchar(); if (ch == 'Y') { printf("確認(rèn)成功\n"); } else { printf("確認(rèn)失敗\n"); } return 0; }
程序中的while( getchar() != ‘\n’)語句會(huì)不斷讀取緩沖區(qū)中的字符,直到把\n讀取走,從而達(dá)到清空緩沖區(qū)的目的。
到此這篇關(guān)于C語言超詳細(xì)講解getchar函數(shù)的使用的文章就介紹到這了,更多相關(guān)C語言getchar函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++ GDI實(shí)現(xiàn)圖片格式轉(zhuǎn)換
GDI+(Graphics Device Interface Plus)是一種用于圖形繪制和圖像處理的應(yīng)用程序編程接口(API),在Windows平臺(tái)上廣泛使用,本文就來介紹一下如何使用GDI實(shí)現(xiàn)圖片格式轉(zhuǎn)換吧2023-12-12C++使用TinyXml實(shí)現(xiàn)讀取XMl文件
常見C/C++?XML解析器有Tinyxml、XERCES、squashxml、xmlite、pugxml、libxml等等,本文為大家介紹的是使用TinyXml實(shí)現(xiàn)讀取XMl文件,需要的可以參考一下2023-06-06C/C++實(shí)現(xiàn)crc碼計(jì)算和校驗(yàn)
循環(huán)冗余校驗(yàn)(Cyclic Redundancy Check, CRC)是一種根據(jù)網(wǎng)絡(luò)數(shù)據(jù)包或計(jì)算機(jī)文件等數(shù)據(jù)產(chǎn)生簡短固定位數(shù)校驗(yàn)碼的一種信道編碼技術(shù)。本文主要介紹了C++實(shí)現(xiàn)crc碼計(jì)算和校驗(yàn)的方法,需要的可以參考一下2023-03-03C++11中std::move、std::forward、左右值引用、移動(dòng)構(gòu)造函數(shù)的測試問題
這篇文章主要介紹了C++11中std::move、std::forward、左右值引用、移動(dòng)構(gòu)造函數(shù)的測試,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09