東坡下載:內(nèi)容最豐富最安全的下載站!

首頁(yè)編程開發(fā)VC(VC++) → C程序緩沖輸入流關(guān)于getchar()與scanf()的思考

C程序緩沖輸入流關(guān)于getchar()與scanf()的思考

相關(guān)文章發(fā)表評(píng)論 來(lái)源:本站原創(chuàng)時(shí)間:2014/2/18 14:53:53字體大。A-A+

更多

作者:不詳點(diǎn)擊:307次評(píng)論:1次標(biāo)簽: C程序緩沖

如題,本文深入了解了下C程序的緩沖輸入方面問(wèn)題。

通常,系統(tǒng)使用行緩沖輸入,這意味著輸入的內(nèi)容會(huì)在您按下回車鍵之時(shí)被傳輸給程序,按下回車鍵的同時(shí)還將傳輸一個(gè)編程時(shí)需要注意的換行字符。ANSIC把緩沖輸入作為標(biāo)準(zhǔn)。

為了說(shuō)明何謂緩沖輸入,特舉了一個(gè)簡(jiǎn)單的例子(別在意例子意義,意在說(shuō)明何謂緩沖輸入):

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main (void)
{
    char ch;
    while (getchar() != 'a')
        continue;
    ch = getchar();
    putchar(ch);
    putchar('\n');
    return 0;
}

輸入下行:

Not alone!

會(huì)發(fā)現(xiàn)輸出為字符l,這就是緩沖輸入的體現(xiàn)。由于簡(jiǎn)單,就不詳講了。

 

緩沖輸入通常給用戶帶來(lái)方便,他提供了在將輸入發(fā)送至程序前對(duì)其進(jìn)行編輯的機(jī)會(huì),但在使用字符輸入時(shí)這會(huì)給編程人員帶來(lái)麻煩。其主要問(wèn)題在于緩沖輸入需要您按下回車鍵來(lái)提交您的輸入。這一動(dòng)作還傳輸一個(gè)程序必須處理的換行符。

尤其是scanf()函數(shù)和getchar()函數(shù)混用的時(shí)候。這是因?yàn)間etchar()讀取每個(gè)字符,包括空格、制表符和換行符;而scanf()在讀取數(shù)字時(shí)則會(huì)跳過(guò)空格、制表符和換行符。為了說(shuō)明它產(chǎn)生的問(wèn)題,舉例如下。該程序讀取一個(gè)字符和兩個(gè)數(shù)作為輸入,然后使用由所輸入的兩個(gè)數(shù)字指定的行數(shù)和列數(shù)來(lái)打印該字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* 程序單1 */
#include <stdio.h>
void display (char cr, int lines, int width);
int main(void)
{
    int ch;         /* 要打印的字符 */
    int rows, cols; /* 行數(shù)和列數(shù) */
    printf ("Enter a character and two integers: \n");
    while ((ch = getchar()) != '\n')
    {
        scanf ("%d %d", &rows, &cols);
        display (ch, rows, cols);
        printf ("Enter another character and two integers: \n");
        printf ("Enter a newline to quit.\n");
    }
    printf ("Bye.\n");
    return 0;
}
void display(char cr, int lines, int width)
{
    int row, col;
    for (row = 1; row <= lines; row++)
    {
        for (col = 1; col <=width; col++)
            putchar(cr);
        putchar('\n');  /* 結(jié)束本行,開始新的一行 */
    }
}

書上也說(shuō)這個(gè)程序是有這大問(wèn)題的,我們也來(lái)看下問(wèn)題在哪。

運(yùn)行時(shí)輸入c 2 3,程序如期打印2行c字符,每行3個(gè)。然后該程序提示輸入第二組數(shù)據(jù),并在您還沒能做出響應(yīng)之前就退出了!這就是緊跟在第一個(gè)輸入行的3后面的那個(gè)換行符所導(dǎo)致的問(wèn)題。scanf()函數(shù)將該換行符留在了輸入隊(duì)列中。而getchar()由于并不跳過(guò)換行符,所以在下一個(gè)循環(huán)時(shí)您輸入其他內(nèi)容之前,這一換行符由getchar()讀出,然后將其賦值給ch,而這正是終止循環(huán)的條件。

書中也給出了解決方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* 程序單2 */
#include <stdio.h>
void display (char cr, int lines, int width);
int main(void)
{
    int ch;         /* 要打印的字符 */
    int rows, cols; /* 行數(shù)和列數(shù) */
    printf ("Enter a character and two integers: \n");
    while ((ch = getchar()) != '\n')
    {
        scanf ("%d %d", &rows, &cols);
        display (ch, rows, cols);
        while (getchar() != '\n')   //添加的語(yǔ)句
            continue;
        printf ("Enter another character and two integers: \n");
        printf ("Enter a newline to quit.\n");
    }
    printf ("Bye.\n");
    return 0;
}
void display(char cr, int lines, int width)
{
    int row, col;
    for (row = 1; row <= lines; row++)
    {
        for (col = 1; col <=width; col++)
            putchar(cr);
        putchar('\n');  /* 結(jié)束本行,開始新的一行 */
    }
}

看到這里,可能就有人說(shuō)了,你這樣照搬照抄有何意思。下面就來(lái)說(shuō)下我自己當(dāng)時(shí)的一些疑惑吧。

在程序單1時(shí),我想了下輸入為cr 2 3時(shí)結(jié)果會(huì)是怎樣,當(dāng)時(shí)真沒想出來(lái)。之后輸入運(yùn)行了下,輸出:

Enter another character and two integers:

Enter a newline to quit.

rrr

rrr

Enter another character and two integers:

Enter a newline to quit.

Bye.

Press any key to continue

當(dāng)時(shí)看到這些時(shí)更加困惑了,為什么會(huì)這樣,c呢?百思不得其解。所以我又在程序單2中輸入cr 2 3,剛開始輸出如下:

Enter another character and two integers:

Enter a newline to quit.

并要求繼續(xù)輸入。當(dāng)時(shí)頗感無(wú)語(yǔ),完全沒懂。然后又慢慢輸入:

1

2

3

結(jié)果:

111

111

Enter another character and two integers:

Enter a newline to quit.

這個(gè)對(duì)了!那么為什么前面輸入cr 2 3時(shí)是那樣輸出呢。按了下?lián)Q行程序結(jié)束后苦思冥想。

 

現(xiàn)在真是想通了,理解的透徹,我來(lái)說(shuō)下吧:

在程序單1輸入cr 2 3時(shí),getchar()讀取了輸入隊(duì)列中的c之后,scanf()無(wú)法讀取r及其之后的字符,只能使用默認(rèn)的值。而這時(shí)的rows和cols的值由于只是在前面聲明并沒有賦值,所以一般是負(fù)的大數(shù)。就假設(shè)這一次循環(huán)的輸入為c -16653 -16652,帶入display程序,當(dāng)然是什么都沒顯示啦。然后輸出了兩行提示信息。而這時(shí)由于緩沖的輸入隊(duì)列中有值,不等您反應(yīng)繼續(xù)帶入,即r 2 3,而這就是之后所輸出的內(nèi)容了。說(shuō)到這里您可以把程序單1中的rows和cols聲明時(shí)分別初始化為1和2,看下結(jié)果就知道了。

至于程序單2,要先知道添加的while語(yǔ)句的作用。它把scanf()輸入后的所有字符,包括換行符都給剔除了。這樣能讓循環(huán)準(zhǔn)備好讀取即將輸入的下一行開始的第一個(gè)字符。也就是說(shuō),您輸入cr 2 3時(shí),他先分別像程序單1中那樣輸入c -16653 -16652,把您輸入的c之后的r 2 3給剔除了包括3之后的換行符,然后輸出兩行提示等待您的再次輸入。

 

PS:好,寫到這里也差不多了(其實(shí)全部手碼的,信不信→_→實(shí)體書還是有麻煩的),今天感悟頗大,收獲頗豐。一直以為C學(xué)的還好,今天拿起以前買的C Primer Plus隨便翻了翻發(fā)現(xiàn)有好多不懂,才知道實(shí)在是想當(dāng)然了,我會(huì)的只是C的語(yǔ)法規(guī)則而已?戳8.5(創(chuàng)建更友好用戶界面)和8.6(輸入確認(rèn)),終于明白了我們大學(xué)生的編程只擁有算法的正確性,而算法的健壯性真的是不堪入目,也終于明白了一個(gè)真正的程序所需要擁有的東西以及編寫一個(gè)能用的軟件有多艱難。下面再給出書中描述的輸入流與字符的關(guān)系,個(gè)人感覺受教了。

 

輸入流與字符:

如下一行輸入:

is 28 12.4

在您眼中,該輸入是一串字符后面跟著一個(gè)整數(shù),然后是一個(gè)浮點(diǎn)值。對(duì)C程序而言,該輸入是一個(gè)字節(jié)流。第一個(gè)字節(jié)是字母i的字符編碼,第二個(gè)字節(jié)是字母s的字符編碼,第三個(gè)字節(jié)是空格字符的字符編碼,第四個(gè)字節(jié)是數(shù)字2的字符編碼,等等。

雖然輸入流由字符組成,但如果您指示了scanf()函數(shù)他就可以將這些字符轉(zhuǎn)換成數(shù)值。例如,考慮下面輸入:

42

如果您在scanf()中使用%c說(shuō)明符,該函數(shù)將只讀取字符4并將其存儲(chǔ)在一個(gè)char類型的變量中。如果您使用%s說(shuō)明符,該函數(shù)會(huì)讀取兩個(gè)字符,即字符4和2,并將它們存儲(chǔ)在一個(gè)字符串中。如果使用%d說(shuō)明符,則scanf()讀取同樣的兩個(gè)字符,但是隨后它會(huì)繼續(xù)計(jì)算與它們相應(yīng)的整數(shù)值為4*10+2,即42;然后講該整數(shù)的二進(jìn)制表示保存到一個(gè)int變量中。如果使用%f說(shuō)明符,則scanf()讀取這兩個(gè)字符,計(jì)算它們對(duì)應(yīng)的數(shù)值42,然后以內(nèi)部浮點(diǎn)表示該值,并將結(jié)果保存在一個(gè)float變量中。

 

C程序?qū)⑤斎胍暈橐粋(gè)外來(lái)字節(jié)的流。簡(jiǎn)言之,輸入由字符組成,但scanf()可以將輸入轉(zhuǎn)換成整數(shù)或浮點(diǎn)值。使用像%d或%f這樣的說(shuō)明符能限制可接受的輸入的字符類型,但getchar()和使用%c的scanf()接收任何字符。

擴(kuò)展知識(shí)

相關(guān)評(píng)論

閱讀本文后您有什么感想? 已有 人給出評(píng)價(jià)!

  • 2791 喜歡喜歡
  • 2101 頂
  • 800 難過(guò)難過(guò)
  • 1219 囧
  • 4049 圍觀圍觀
  • 5602 無(wú)聊無(wú)聊
熱門評(píng)論
最新評(píng)論
第 1 樓 本機(jī)地址CZ88.NET 網(wǎng)友 客人 發(fā)表于: 2017/2/23 22:07:05
为什么“添加的while语句能使程序剔除scanf( )输入后的所有字符,包括换行符”。怎么解释?

支持( 0 ) 蓋樓(回復(fù))

發(fā)表評(píng)論 查看所有評(píng)論(1)
昵稱:
表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)