标签:
输入操作的原理,程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。正因为cin函数是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin函数会直接取得这些残留数据而不会请求键盘输入,这就是例子中为什么会出现输入语句失效的原因!
cin输入结束的条件:Enter、Space、Tab。cin对这些结束符的处理:丢弃缓冲区中这些字符。与cin.get()不同。
案例1:
#include <iostream> using namespace std; int main() { int m, n; cin >> m; cin >> n; cout << m << n << endl; return 0; }
测试正常输入:
测试异常输入:
案例2:string的输入
void main() { string str1; cin >> str1; //遇到空格的地方就停止字符串的读取输入 cout << str1 << endl; cin.get(); getline(cin, str1); cout << str1 << endl; }
测试:
可以看出cin是遇到“空格”就停止读取输入,并且cin是从第一个“非空格字符”开始读取;
而getline则是直接从第一个字符开始读取(无论是不是空格,都要读入),并且getline是遇到“回车”停止读入;
当把上述代码中 的cin.get()去掉,则输入“123”----》回车 后,getline直接读取“回车”,运行完毕!
案例3:
int main() { char str[8]; cin.getline(str, 5); cout << str << endl; cin.getline(str, 5); cout << str << endl; return 0; }
测试一:abcd (回车)abcd (输出)efgh(回车)efgh (输出)当用户第一次输入的字符串字符数小于4时,程序执行正常!
测试二:abcdefgh (回车)abcd (输出) (输出-换行)当用户第一次输入的字符数字符数大于4时,第一个字符串接受输入的前四个字符,而第二次的输入操作没有执行,第二个字符串输出为空。
案例1:
int main() { char str1; char str2; str1 = cin.get(); //读取单个字符,在屏幕输入 str2 = cin.get(); cout << str1 << str2 << endl; //输出刚刚载入的单个字符 system("pause"); //进行暂停,否则会一闪而过 }
输入:abcd 输出:ab
既然cin.get()是读取第一个字符,那str2为什么不也是a呢?
原理如下:
案例2:
{ char str1[10], str2[10]; cin >> str1; cin >> str2; cout << str1 << endl; cout << str2 << endl; return 0; }
测试一输入:abcd[Enter]efgh[Enter] 输出:abcdefgh【分析】输入遇到回车符结束,很正常。
测试二输入:abcd efgh 输出:abcdefgh 【分析】第一次读取字符串时遇到空格则停止了,将abcd读入str1,并舍弃了空格,将后面的字符串给了第二个字符串。这证明了cin读入数据遇到空格结束;并且丢弃空格符;缓冲区有残留数据室,读入操作直接从缓冲区中取数据。
案例3:
int main() { char str1; char str2; str1 = cin.get(); //读取单个字符,在屏幕输入 cin.get(); str2 = cin.get(); cout << str1 << str2 << endl; //输出刚刚载入的单个字符 }
输入:abcd 输出:ac
案例4:
} char c1, c2; cin.get(c1); cin.get(c2); cout << c1 << " " << c2 << endl; // 打印两个字符 cout<<(int)c1<<""<<(int)c2<<endl; // 打印这两个字符的ASCII值 return 0; }
测试一输入:a[Enter]输出:a 97 10【分析】会发现只执行了一次从键盘输入,显然第一个字符变量取的‘a‘,第二个变量取的是Enter(ASCII值为10),这是因为该函数不丢弃上次输入结束时的Enter字符,所以第一次输入结束时缓冲区中残留的是上次输入结束时的Enter字符!
测试二输入:a b[Enter]输出:a 97 32【分析】显然第一个字符变量取的‘a‘,第二个变量取的是Space(ASCII值为32)。原因同上,没有丢弃Space字符。
案例5:
{ char ch, a[20]; cin.get(a, 5); cin >> ch; cout << a << endl; cout << (int)ch << endl; return 0; }</span>
测试一输入:12345[Enter]输出:123453【分析】第一次输入超长,字符串按长度取了"1234",而‘5‘仍残留在缓冲区中,所以第二次输入字符没有从键盘读入,而是直接取了‘5‘,所以打印的ASCII值是53(‘5‘的ASCII值)。
测试二输入:1234[Enter]a[Enter]输出:123497【分析】第二次输入有效,说明该函数把第一次输入后的Enter丢弃了!
cin.getline()与 cin.get(array_name,Arsize)的读取方式差不多,以Enter结束,但是接受空格字符。按照长度(Arsize)读取字符, 会丢弃最后的Enter字符。但是这两个函数是有区别的:cin.get(array_name, Arsize)当输入的字符串超长时,不会引起cin函数的错误,后面的cin操作会继续执行,只是直接从缓冲区中取数据。但是cin.getline()当输入超长时,会引起cin函数的错误,后面的cin操作将不再执行。
char str1[200]; char str2[200]; cin.getline(str1, sizeof(str1), 'X'); //以单个英文字母'X'作为终止标识符 cin.getline(str2, sizeof(str2), 'Y'); //以单个英文字母'Y'作为终止标识符 cout << "第一行是:" << str1 << endl; //输出 cout << "第二行是:" << str2 << endl; system("pause"); }
ios类定义了这四个常量badbit, eofbit, failbit, goodbit,其实这四个标志常量就是取对应标志位的掩码,也即输入的四种异常情况!
以上四个常量对应的取值为:
ios::badbit 输入(输出)流出现致命错误,不可挽回
ios::eofbit 已经到达文件尾
ios::failbit 输入(输出)流出现非致命错误,可挽回
ios::goodbit 流状态完全正常, 各异常标志位都为0
我们可以用输出语句来验证这几个常量的值:
cout << ios:: failbit << endl; //2
cout << ios:: eofbit << endl; //1
cout << ios:: badbit << endl; //4
cout << ios:: goodbit << endl; //0
cin.fail()、cin.clear()、cin.sync()例子:
int main() { int a; while (true) { cin >> a; if (!cin) //条件可改写为cin.fail() { cout << "输入类型错误,请重新输入!" << endl; cin.clear(); //复为标志,将cin中的所有标志设置为有效状态 cin.sync(); //清空流 } else { cout << a << endl; break; } } system("pause"); }
上面的cin默认值为非0,当输入为非整形时,它的状态标识符改为fail(即0),再用cin.clear()让错误标识改回为非0,可以继续输入,再清空流数据继续输入。如果没有了cin.clear(),则会进入死循环,其过程为我们输入了英文字母,它的状态标识便为fail,当运行到条件判断时,便总是回到错误的条件表示里,并且再也没有办法输入,因为错误的表示关闭了cin,所以会进入死循环。可以分别注释掉cin.clear()和cin.sync()进行验证。
这个函数用来丢弃输入缓冲区中的字符,第一参数定义一个数(_Count),第二个参数定义一个字符变量(_Delim)。下面解释一下函数是怎样执行的:函数不停的从缓冲区中取一个字符,并判断是不是_Delim,如果不是则丢弃并进行计数,当计数达到_Count退出,如果是则丢弃字符退出。
这个函数的默认值,第一个参数默认为1,第二个参数默认为EOF。所以cin.ignore()就是丢弃缓冲区中的第一个字符。
用cin.get()读取字符,get函数不丢弃回车符,所以回车符仍残留在缓冲区中,导致第二次读取数据直接从缓冲区中取得回车符!既然cin.get()不会自动丢弃输入结束时的回车符,这里我们就用ignore()函数,手动丢弃回车符!
int main() { char c1, c2; cin.get(c1); cin.ignore(); // 用该函数的默认情况,丢弃一个字符,即上次输入结束的回车符 cin.get(c2); cout << c1 << " " << c2 << endl; // 打印两个字符 cout << (int)c1 << " " << (int)c2 << endl; // 打印这两个字符的ASCII值 return 0; }
清空整个缓冲区:——其实该函数最常用的方式是这样的,将第一个参数设的非常大,将第二个参数设为‘\n‘,这样就可以缓冲区中回车符中的所有残留数据,因为一般情况下前面输入残留的数据是没有用的,所以在进行新一次输入操作前将缓冲区中所有数据清空是比较合理。
如:cin.ignore(1024, ‘\n‘);
标签:
原文地址:http://blog.csdn.net/songshimvp1/article/details/51206429