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 */
