基础 - 字符读取函数scanf、getchar、gets、cin(清空缓存区解决单字符回车问题)

时间:2021-11-23 22:29:08

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,输出:

基础 - 字符读取函数scanf、getchar、gets、cin(清空缓存区解决单字符回车问题)

Sub_1_3输入a,输出:

基础 - 字符读取函数scanf、getchar、gets、cin(清空缓存区解决单字符回车问题)

为什么这个形式呢?

先说一下输入操作原理:程序的输入都建有一个缓冲区,即输入缓冲区。当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入,

这里的10恰好是回车符,scanf()和getchar()函数是从输入流缓冲区中读取值的,而并非从键盘(也就是终端)缓冲区读取。而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,所以第一次接受输入时取走字符后会留下字符\n,这样第二次的读入函数直接从缓冲区中把\n取走了。

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

 //scanf()读取字符串 空格问题
void Sub_2_1()
{
char str1[], str2[];
scanf("%s",str1);
printf("%s\n",str1);
scanf("%s",str2);
printf("%s\n",str2); //空格问题 //hello world ->
//hello
//world
/*第一次输入Hello world!后,
字符串Hello world!都会被读到输入缓冲区中,
而scanf()函数取数据是遇到回车、空格、TAB就会停止,
也就是第一个scanf()会取出"Hello",而"world!"还在缓冲区中,
这样第二个scanf会直接取出这些数据,而不会等待从终端输入。*/ //scanf()读取字符串会舍弃最后的回车符!
//hello ->
//hello -> } //gets()读取字符串 接受空格
void Sub_2_2()
{
char str1[], str2[];
gets(str1);
printf("%s\n",str1);
gets(str2);
printf("%s\n",str2); }

先来看Sub_2_1,程序的功能是读入一个字符串输出,在读入一个字符串输出。可我们会发现输入的字符串中不能出现空格,例如:

基础 - 字符读取函数scanf、getchar、gets、cin(清空缓存区解决单字符回车问题)

这个问题的原因跟0x01类似,第一次输入Hello world后,字符串Hello world都会被读到输入缓冲区中,而scanf()函数取数据是遇到回车、空格、TAB就会停止,也就是第一个scanf()会取出"Hello",而"world"还在缓冲区中,这样第二个scanf会直接取出这些数据,而不会等待从终端输入

Sub_2_2,gets不会有这个问题:

基础 - 字符读取函数scanf、getchar、gets、cin(清空缓存区解决单字符回车问题)

总结:

读取字符时:
scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);
getchar()以Enter结束输入,也不会舍弃最后的回车符;
读取字符串时:
scanf()以Space、Enter、Tab结束一次输入
gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!
第二:为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:
方法1:C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!
这个函数是fflush(stdin)。//似乎并没有用。

//setbuf(stdin, NULL);//使stdin输入流由默认缓冲区转为无缓冲区

方法2:自己取出缓冲区里的残留数据。

源代码(包括解决单字符回车问题):

 #include <windows.h>
#include <IOSTREAM> using namespace std; void Sub_1_1();
void Sub_1_2();
void Sub_1_3(); void Sub_2_1();
void Sub_2_2(); int main ()
{
//scanf getchar
//Sub_1_1();
Sub_1_2();
//Sub_1_3(); /*****/
//scanf gets
// Sub_2_1();
//Sub_2_2();
} //setbuf(stdin, NULL);//使stdin输入流由默认缓冲区转为无缓冲区 //scanf读取字符 回车问题
void Sub_1_1()
{
char v1,v2; scanf("%c", &v1);
//setbuf(stdin, NULL); //解决回车问题
scanf("%c", &v2);
//setbuf(stdin, NULL); //解决回车问题
printf("%d %d\n", v1, v2); //回车问题
} /* scanf()和getchar()函数是从输入流缓冲区中读取值的,
而并非从键盘(也就是终端)缓冲区读取。
而读取时遇到回车(\n)而结束的,这个\n会一起读入输入流缓冲区的,
所以第一次接受输入时取走字符后会留下字符\n,
这样第二次的读入函数直接从缓冲区中把\n取走了,显然读取成功了,
所以不会再从终端读取! */ //getchar读取字符 回车问题
void Sub_1_2()
{
char ch1, ch2;
//setbuf(stdin, NULL); //解决回车问题
ch1 = getchar();
//setbuf(stdin, NULL); //解决回车问题
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; } //scanf()读取字符串 空格问题
void Sub_2_1()
{
char str1[], str2[];
scanf("%s",str1);
printf("%s\n",str1);
scanf("%s",str2);
printf("%s\n",str2); //空格问题 //hello world ->
//hello
//world
/*第一次输入Hello world!后,
字符串Hello world!都会被读到输入缓冲区中,
而scanf()函数取数据是遇到回车、空格、TAB就会停止,
也就是第一个scanf()会取出"Hello",而"world!"还在缓冲区中,
这样第二个scanf会直接取出这些数据,而不会等待从终端输入。*/ //scanf()读取字符串会舍弃最后的回车符!
//hello ->
//hello -> } //gets()读取字符串 接受空格
void Sub_2_2()
{
char str1[], str2[];
gets(str1);
printf("%s\n",str1);
gets(str2);
printf("%s\n",str2); } //总结
/*
读取字符时:
scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);
getchar()以Enter结束输入,也不会舍弃最后的回车符;
读取字符串时:
scanf()以Space、Enter、Tab结束一次输入
gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!
第二:为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:
方法1:C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!
这个函数是fflush(stdin)//似乎并没有用。
//setbuf(stdin, NULL);//使stdin输入流由默认缓冲区转为无缓冲区
方法2:自己取出缓冲区里的残留数据。
*/