天天看點

C語言 getchar()原理及易錯點解析一.getchar()系列

文章目錄

  • 一.getchar()系列
    • 1.getchar()工作原理及作用
    • 2.使用getchar()清理回車\n
    • 3.使用getchar()清理緩存
    • 4.混合scanf()與getchar()

一.getchar()系列

1.getchar()工作原理及作用

  • 工作原理:getchar()是stdio.h中的庫函數,它的作用是從stdin流中讀入一個字元,也就是說,如果stdin有資料的話不用輸入它就可以直接讀取了,第一次getchar()時,确實需要人工的輸入,但是如果你輸了多個字元,以後的getchar()再執行時就會直接從緩沖區中讀取了。

    實際上是 輸入裝置->記憶體緩沖區->getchar()

    你按的鍵是放進緩沖區了,然後供程式getchar()

    你有沒有試過按住很多鍵然後等一會兒會滴滴滴滴響,就是緩沖區滿了,你後頭按的鍵沒有存進緩沖區.

    鍵盤輸入的字元都存到緩沖區内,一旦鍵入回車,getchar就進入緩沖區讀取字元,一次隻傳回第一個字元作為getchar函數的值,如果有循環或足夠多的getchar語句,就會依次讀出緩沖區内的所有字元直到’\n’.要了解這一點,之是以你輸入的一系列字元被依次讀出來,是因為循環的作用使得反複利用getchar在緩沖區裡讀取字元,而不是getchar可以讀取多個字元,事實上getchar每次隻能讀取一個字元.如果需要取消’\n’的影響,可以用getchar();來清除,這裡getchar();隻是取得了’\n’但是并沒有賦給任何字元變量,是以不會有影響,相當于清除了這個字元.

  • 作用1:從緩沖區讀走一個字元,相當于清除緩沖區。
  • 作用2:前面的scanf()在讀取輸入時會在緩沖區中留下一個字元’\n’(輸入完按Enter鍵所緻),是以如果不在此加一個getchar()把這個回車符取走的話,接下來的scanf()就不會等待從鍵盤鍵入字元,而是會直接取走這個“無用的”回車符,進而導緻讀取有誤。

2.使用getchar()清理回車\n

這個問題轉載自n_s_X14,但是作者在文章最後留了一個問題,現在在這裡給大家解釋一下原因。

文章的源碼為:

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示使用者輸入第一個字元串
    scanf("%s",m);                         //擷取使用者第一個輸入字元串
    printf("you input str is :%s\n",m);    //輸出使用者的輸入的第一個字元串
    printf("input second char :\n");        //提示使用者輸入第二個字元
    scanf("%c",&n);                         //擷取使用者的第二個字元
    printf("now you input second char is :%c\n",n);//輸出使用者輸入的第二個字元
    return 0;
    
}
           

Output:

please input first str:
abc
you input str is :abc
input second char :
now you input second char is :

Program ended with exit code: 0
           

問題:我們第一次輸入abc後成功列印出來了

you input str is :abc

,但是執行到

printf("input second char :\n");

時,還沒等到第二次輸入就列印出來了。這是為什麼??

原因:

其實在我們第一次輸入并按下回車的時候,控制台一共獲得了四個字元,分别是:a、b、c、回車(enter)。但是因為scanf()方法遇到非字元的時候會結束從控制台的擷取,是以在輸入’abc’後,按下 ‘回車(enter)’ 的同時,将’abc’這個值以字元串的形式指派給了類型為 ‘char’ 的 ‘m’ 數組,将使用過後的字元串: ‘回車(enter)’ 儲存在控制台輸入的緩沖區,然後繼續執行下一段輸出代碼,然後又要求使用者輸入。此時,因為上一次被使用過後的字元串被儲存在緩沖區,現在scanf()方法從控制台的緩沖區擷取上一次被使用過後的字元串,并隻截取第一個字元: ‘回車(enter)’ ,此時控制台緩沖區才算使用完了。是以在看似被跳過的輸入,其實已經scanf()方法已經擷取了我們的輸入了,這個輸入就是一個 ‘回車(enter)’ 。

解決問題:

使用getchar()方法,清除掉abc後面的緩存(回車enter)。

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示使用者輸入第一個字元串
    scanf("%s",m);                         //擷取使用者第一個輸入字元串
    printf("you input str is :%s\n",m);    //輸出使用者的輸入的第一個字元串
    getchar();
    printf("input second char :\n");        //提示使用者輸入第二個字元
    scanf("%c",&n);                         //擷取使用者的第二個字元
    printf("now you input second char is :%c\n",n);//輸出使用者輸入的第二個字元
    return 0;
    
}
           

Output:

please input first str:
abc
you input str is :abc
input second char :
de
now you input second char is :d
Program ended with exit code: 0
           

3.使用getchar()清理緩存

文章結束時留了一個問題:如果在第一次輸入ab後加一個空格再回車,又會出現原來的問題,即程式隻輸出了ab後就自動跳過下一次的輸入之間退出了,控制台輸出如下圖所示。

C語言 getchar()原理及易錯點解析一.getchar()系列

原因:

  1. 在擷取使用者第一個輸入字元串時,

    scanf("%s",&m);

    ,我們用%s作為轉換說明,%s的作用是“把輸入解釋成字元串。從第一個非空白字元開始,到下一個空白字元之前的所有字元都是輸入。”是以scanf把輸入的

    ab空格+回車

    就了解為

    ab+回車

    (ab後面沒有空格),但是依然以

    ab空格+回車

    的形式存儲在緩存區。
  2. 我們輸入

    ab空格+回車

    ,在緩存區是這樣存放的:
    C語言 getchar()原理及易錯點解析一.getchar()系列

    其中,第三格存放的為空格鍵。

    當程式運作完

    getchar();

    後,隻清除了第三格中的空格鍵,因為一次執行

    getchar();

    隻清除一個緩存,留下了第四格中的Enter鍵,是以再次出現了同樣的問題。

解決問題:那麼就是說隻要運作兩次

getchar();

,清除掉第三格和第四格就可以正常了。

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示使用者輸入第一個字元串
    scanf("%s",m);                         //擷取使用者第一個輸入字元串
    printf("you input str is :%s\n",m);    //輸出使用者的輸入的第一個字元串
    
    getchar();                              //第一次清除緩存
    getchar(); 								//第二次清除緩存
    
    printf("input second char :\n");        //提示使用者輸入第二個字元
    scanf("%c",&n);                         //擷取使用者的第二個字元
    printf("now you input second char is :%c\n",n);//輸出使用者輸入的第二個字元
    return 0;
    
}
           

Output:

C語言 getchar()原理及易錯點解析一.getchar()系列

由此可見,當我們第一次輸入ab空格+回車後,程式正常運作。

進一步:如果我們輸入的是

a空格b+回車

scanf("%s",m);

這一步隻能讀取到a,因為a後面有空格。但是

a空格b+回車

在緩沖區這樣存放:

C語言 getchar()原理及易錯點解析一.getchar()系列

是以,如果想要程式正常運作則需要在輸出使用者的輸入的第一個字元串後加入三次

getchar();

操作,即删除掉第二,第三,第四格的内容。

問題:如果我們輸入

a空格bbbbbbbb+回車

,那可能需要無數個

getchar();

來清除緩存,這時應該怎麼辦??

解決方法:加入while循環

while(getchar()!='\n') continue;

#include <stdio.h>

int main(void){
    char m[40];
    char n;
    printf("please input first str:\n");    //提示使用者輸入第一個字元串
    scanf("%s",m);                         //擷取使用者第一個輸入字元串
    printf("you input str is :%s\n",m);    //輸出使用者的輸入的第一個字元串
    
    while(getchar()!='\n')					//通過while循環删除緩存
        continue;
        
    printf("input second char :\n");        //提示使用者輸入第二個字元
    scanf("%c",&n);                         //擷取使用者的第二個字元
    printf("now you input second char is :%c\n",n);//輸出使用者輸入的第二個字元
    return 0;
    
}
           

這時,我們輸入

a空格bbbbbbbb+回車

,程式正常運作。

C語言 getchar()原理及易錯點解析一.getchar()系列

解析:

while(getchar()!='\n')
        continue;
           

可以看出這段代碼代替了無數個getchar(),他的作用是跳過剩餘的輸入行

C語言 getchar()原理及易錯點解析一.getchar()系列

第一次while循環消除第二格緩存,第二次while循環消除第三格緩存……直到第八次。最後一次同樣,getchar()也消除了回車。

while(getchar()!='\n')

可以拆分成兩步,

  • 第一步調用

    getchar()

    方法(這裡getchar();隻是取得了’\n’但是并沒有賦給任何字元變量,是以不會有影響,相當于清除了這個字元)。
  • 第二步判斷擷取到的緩存是否等于’\n’。

4.混合scanf()與getchar()

假設程式要求用getchar()處理字元輸入,用scanf()處理數值輸入,這兩個函數都能很好的完成任務,但是不能混合使用。 因為getchar()讀取每個字元,包括空格、制表符和換行符;而scanf()在讀取數字時則會跳過空格、制表符和換行符。

例:

要求使用者輸入一個字母和兩個數字,輸出以第一個數字為行數,第二個數字為列數,以字母為内容的數列,要求可以不斷輸入直至鍵入回車退出程式:

#include <stdio.h>
void display(char cr,int lines,int width);
int main(int argc, const char * argv[]) {
   
    int ch;
    int rows,cols;
    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');
            }
}
           

output:

C語言 getchar()原理及易錯點解析一.getchar()系列

我們發現,在第一次輸入成功列印後,程式自動退出。這明顯不符合我們的題目要求。

原因是,輸入的c23其實是

c23+換行符

,scanf()函數把這個換行符留在了緩存中。getchar()不會跳過換行符,是以在進入下一輪疊代時,還沒來得及輸入字元,它就讀取了換行符,然後将其指派給了ch。而ch是換行符正式終止循環的條件。

如何改進??

  1. 我們需要删除scanf()函數留在緩存中的換行符即可。
  2. 在if語句中使用一個break語句,可以在scanf()的傳回值不等于2時終止程式,即如果一個或兩個輸入值不是整數或者遇到檔案結尾就終止程式。
#include <stdio.h>
void display(char cr,int lines,int width);
int main(int argc, const char * argv[]) {
   
    int ch;
    int rows,cols;
    printf("Enter a character and two integers:\n");
    while((ch=getchar())!= '\n'){
        if( scanf("%d %d", &rows,&cols)!=2 ){
            break;
        }
        display(ch, rows, cols);
        
        while(getchar()!='\n'){
            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');
            }
}
           

Output:

C語言 getchar()原理及易錯點解析一.getchar()系列

題外話:

scanf()中轉化符的問題

C語言 getchar()原理及易錯點解析一.getchar()系列
C語言 getchar()原理及易錯點解析一.getchar()系列

問題:從上面兩張圖檔中可以看出,當

scanf("%d",&c);

改為

scanf("%c",&c);

時,控制台中出現了圖二的問題。character為什麼為空白??

原因:

如果格式是%c,那麼任何字元都是它想要的,是以第二個程式中的第二個scanf("%c")會得到‘+’後面的空格’ '。如果格式是%d,則會忽略任何空白字元(空格、回車、制表符等),忽略的意思是,從緩沖區裡删除,但并不儲存;如果遇到數字,則拿出并儲存給後面的整數,也就是說%d的時候,scanf想要的字元是數字和空白符。是以第一個程式裡的第二個scanf("%d")忽略掉了空格,正确輸入了數字。

繼續閱讀