基礎 - 字符讀取函數scanf、getchar、gets、cin(清空緩存區解決單字符回車問題)


0x01 scanf、getchar、cin讀取單字符:

如下:

//scanf讀取字符 回車問題
void Sub_1_1()
{
    char v1,v2;
    scanf("%c", &v1);
    scanf("%c", &v2);
    printf("%d %d\n", v1, v2);

    //回車問題
}

/* scanf()和getchar()函數是從輸入流緩沖區中讀取值的,
    而並非從鍵盤(也就是終端)緩沖區讀取。
    而讀取時遇到回車(\n)而結束的,這個\n會一起讀入輸入流緩沖區的,
    所以第一次接受輸入時取走字符后會留下字符\n,
    這樣第二次的讀入函數直接從緩沖區中把\n取走了,顯然讀取成功了,
    所以不會再從終端讀取! */

//getchar讀取字符 回車問題
void Sub_1_2()
{
    char ch1, ch2;
    ch1 = getchar();
    ch2 = getchar();
    printf("%d %d\n", ch1, ch2);

    //回車問題
}

//cin讀取單字符 無回車問題
void Sub_1_3()
{
    char ch1, ch2;
    cin >> ch1;
    cin >> ch2;

    cout << ch1 << endl;
    cout << ch2 << endl;

}

例如:

Sub_1_1、Sub_1_2 輸入 a,輸出:

Sub_1_3輸入a,輸出:

 

為什么這個形式呢?

先說一下輸入操作原理:程序的輸入都建有一個緩沖區,即輸入緩沖區。當一次鍵盤輸入結束時會將輸入的數據存入輸入緩沖區,而cin函數直接從輸入緩沖區中取數據。正因為cin函數是直接從緩沖區取數據的,所以有時候當緩沖區中有殘留數據時,cin函數會直接取得這些殘留數據而不會請求鍵盤輸入,

 這里的10恰好是回車符,scanf()和getchar()函數是從輸入流緩沖區中讀取值的,而並非從鍵盤(也就是終端)緩沖區讀取。而讀取時遇到回車(\n)而結束的,這個\n會一起讀入輸入流緩沖區的,所以第一次接受輸入時取走字符后會留下字符\n,這樣第二次的讀入函數直接從緩沖區中把\n取走了。

 

 0x02 scanf()和gets()讀取字符串:

 1 //scanf()讀取字符串 空格問題
 2 void Sub_2_1()
 3 {
 4     char str1[20], str2[20];
 5     scanf("%s",str1);
 6     printf("%s\n",str1);
 7     scanf("%s",str2);
 8     printf("%s\n",str2);
 9 
10     //空格問題 
11 
12     //hello world -> 
13     //hello
14     //world
15     /*第一次輸入Hello world!后,
16     字符串Hello world!都會被讀到輸入緩沖區中,
17     而scanf()函數取數據是遇到回車、空格、TAB就會停止,
18     也就是第一個scanf()會取出"Hello",而"world!"還在緩沖區中,
19     這樣第二個scanf會直接取出這些數據,而不會等待從終端輸入。*/
20 
21     //scanf()讀取字符串會舍棄最后的回車符!
22     //hello -> 
23     //hello -> 
24 
25 }
26 
27 //gets()讀取字符串 接受空格
28 void Sub_2_2()
29 {
30     char str1[20], str2[20];
31     gets(str1);
32     printf("%s\n",str1);
33     gets(str2);
34     printf("%s\n",str2);
35 
36 }

 

 先來看Sub_2_1,程序的功能是讀入一個字符串輸出,在讀入一個字符串輸出。可我們會發現輸入的字符串中不能出現空格,例如:

這個問題的原因跟0x01類似,第一次輸入Hello world后,字符串Hello world都會被讀到輸入緩沖區中,而scanf()函數取數據是遇到回車、空格、TAB就會停止,也就是第一個scanf()會取出"Hello",而"world"還在緩沖區中,這樣第二個scanf會直接取出這些數據,而不會等待從終端輸入

 Sub_2_2,gets不會有這個問題:

 

 

 總結:


讀取字符時:
scanf()以Space、Enter、Tab結束一次輸入,不會舍棄最后的回車符(即回車符會殘留在緩沖區中);
getchar()以Enter結束輸入,也不會舍棄最后的回車符;
讀取字符串時:
scanf()以Space、Enter、Tab結束一次輸入
gets()以Enter結束輸入(空格不結束),接受空格,會舍棄最后的回車符!
第二:為了避免出現上述問題,必須要清空緩沖區的殘留數據,可以用以下的方法解決:
方法1:C語言里提供了函數清空緩沖區,只要在讀數據之前先清空緩沖區就沒問題了!
這個函數是fflush(stdin)。//似乎並沒有用。

//setbuf(stdin, NULL);//使stdin輸入流由默認緩沖區轉為無緩沖區


方法2:自己取出緩沖區里的殘留數據。

 

 源代碼(包括解決單字符回車問題):

  1 #include <windows.h>
  2 #include <IOSTREAM>
  3 
  4 using namespace std;
  5 
  6 void Sub_1_1();
  7 void Sub_1_2();
  8 void Sub_1_3();
  9 
 10 void Sub_2_1();
 11 void Sub_2_2();
 12 
 13 int main ()
 14 {
 15     //scanf getchar 
 16     //Sub_1_1();
 17     Sub_1_2();
 18     //Sub_1_3();
 19     
 20 
 21 /*****/
 22     //scanf gets
 23 //    Sub_2_1();
 24     //Sub_2_2();
 25 }
 26 
 27 //setbuf(stdin, NULL);//使stdin輸入流由默認緩沖區轉為無緩沖區  
 28 
 29 //scanf讀取字符 回車問題
 30 void Sub_1_1()
 31 {
 32     char v1,v2;
 33     
 34     scanf("%c", &v1);
 35     //setbuf(stdin, NULL); //解決回車問題
 36     scanf("%c", &v2);
 37     //setbuf(stdin, NULL); //解決回車問題
 38     printf("%d %d\n", v1, v2);
 39 
 40     //回車問題
 41 }
 42 
 43 /* scanf()和getchar()函數是從輸入流緩沖區中讀取值的,
 44     而並非從鍵盤(也就是終端)緩沖區讀取。
 45     而讀取時遇到回車(\n)而結束的,這個\n會一起讀入輸入流緩沖區的,
 46     所以第一次接受輸入時取走字符后會留下字符\n,
 47     這樣第二次的讀入函數直接從緩沖區中把\n取走了,顯然讀取成功了,
 48     所以不會再從終端讀取! */
 49 
 50 //getchar讀取字符 回車問題
 51 void Sub_1_2()
 52 {
 53     char ch1, ch2;
 54     //setbuf(stdin, NULL); //解決回車問題
 55     ch1 = getchar();
 56     //setbuf(stdin, NULL); //解決回車問題
 57     ch2 = getchar();
 58     printf("%d %d\n", ch1, ch2);
 59 
 60     //回車問題
 61 }
 62 
 63 //cin讀取單字符 無回車問題
 64 void Sub_1_3()
 65 {
 66     char ch1, ch2;
 67     cin >> ch1;
 68     cin >> ch2;
 69 
 70     cout << ch1 << endl;
 71     cout << ch2 << endl;
 72 
 73 }
 74 
 75 //scanf()讀取字符串 空格問題
 76 void Sub_2_1()
 77 {
 78     char str1[20], str2[20];
 79     scanf("%s",str1);
 80     printf("%s\n",str1);
 81     scanf("%s",str2);
 82     printf("%s\n",str2);
 83 
 84     //空格問題 
 85 
 86     //hello world -> 
 87     //hello
 88     //world
 89     /*第一次輸入Hello world!后,
 90     字符串Hello world!都會被讀到輸入緩沖區中,
 91     而scanf()函數取數據是遇到回車、空格、TAB就會停止,
 92     也就是第一個scanf()會取出"Hello",而"world!"還在緩沖區中,
 93     這樣第二個scanf會直接取出這些數據,而不會等待從終端輸入。*/
 94 
 95     //scanf()讀取字符串會舍棄最后的回車符!
 96     //hello -> 
 97     //hello -> 
 98 
 99 }
100 
101 //gets()讀取字符串 接受空格
102 void Sub_2_2()
103 {
104     char str1[20], str2[20];
105     gets(str1);
106     printf("%s\n",str1);
107     gets(str2);
108     printf("%s\n",str2);
109 
110 }
111 
112 
113 //總結
114 /*
115 讀取字符時:
116 scanf()以Space、Enter、Tab結束一次輸入,不會舍棄最后的回車符(即回車符會殘留在緩沖區中);
117 getchar()以Enter結束輸入,也不會舍棄最后的回車符;
118 讀取字符串時:
119 scanf()以Space、Enter、Tab結束一次輸入
120 gets()以Enter結束輸入(空格不結束),接受空格,會舍棄最后的回車符!
121 第二:為了避免出現上述問題,必須要清空緩沖區的殘留數據,可以用以下的方法解決:
122 方法1:C語言里提供了函數清空緩沖區,只要在讀數據之前先清空緩沖區就沒問題了!
123 這個函數是fflush(stdin)//似乎並沒有用。
124 //setbuf(stdin, NULL);//使stdin輸入流由默認緩沖區轉為無緩沖區 
125 方法2:自己取出緩沖區里的殘留數據。
126 */

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM