基础
0x01 scanf、getchar、cin读取单字符:
如下:
//scanf读取字符 回车问题 void Sub_1_1() { char v1,v2; scanf("%c", &v1); scanf("%c", &v2); printf("%d %d ", v1, v2); //回车问题 } /* scanf()和getchar()函数是从输入流缓冲区中读取值的, 而并非从键盘(也就是终端)缓冲区读取。 而读取时遇到回车( )而结束的,这个 会一起读入输入流缓冲区的, 所以第一次接受输入时取走字符后会留下字符 , 这样第二次的读入函数直接从缓冲区中把 取走了,显然读取成功了, 所以不会再从终端读取! */ //getchar读取字符 回车问题 void Sub_1_2() { char ch1, ch2; ch1 = getchar(); ch2 = getchar(); printf("%d %d ", 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()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车( )而结束的,这个 会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符 ,这样第二次的读入函数直接从缓冲区中把 取走了。
0x02 scanf()和gets()读取字符串:
1 //scanf()读取字符串 空格问题 2 void Sub_2_1() 3 { 4 char str1[20], str2[20]; 5 scanf("%s",str1); 6 printf("%s ",str1); 7 scanf("%s",str2); 8 printf("%s ",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 ",str1); 33 gets(str2); 34 printf("%s ",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 ", v1, v2); 39 40 //回车问题 41 } 42 43 /* scanf()和getchar()函数是从输入流缓冲区中读取值的, 44 而并非从键盘(也就是终端)缓冲区读取。 45 而读取时遇到回车( )而结束的,这个 会一起读入输入流缓冲区的, 46 所以第一次接受输入时取走字符后会留下字符 , 47 这样第二次的读入函数直接从缓冲区中把 取走了,显然读取成功了, 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 ", 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 ",str1); 81 scanf("%s",str2); 82 printf("%s ",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 ",str1); 107 gets(str2); 108 printf("%s ",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 */