C++中,头文件iostream.h中定义了cin,cout, cerr, clog等4个流对象,cin是输入流,cout, cerr, clog是输出流。cin是istream类的对象,它从标准输入设备(键盘)获取数据,程序中的变量通过流提取符“>>”从流中提取数据。
注意的是,在输入完成数据再按回车键后,该行数据才被送入键盘缓冲区,形成输入流,提取运算符“>>”才能从中提取数据。
当输入流cin处于出错状态时,如果测试cin的值,可以发现它的值为false(假),则cin为0值;如果输入流在正常状态,cin的值为true(真),即cin为一个非0的值。如下所示:
if(!cin) // 流cin处于出错状态,无法正常提取数据
cout <<"Error";
此时,通过一个案例演示下cin为false时情况。当正常输入float类型内容时,一直循环输出;当输入非float类型致使cin出错为0时,而结束循环操作。代码如下:
#include <iostream>
using namespace std;
int main(){
float grade = -1;
do{
if(grade < 0) {
// nothing...
}
else if(grade >= 85) cout <<grade <<" Good!" <<endl;
else if(grade < 60) cout <<grade <<" Fail!" <<endl;
else cout <<grade <<endl;
cout <<"enter grade:";
} while(cin >> grade);
cout <<"The end." <<endl;
return 0;
}
每次提出浮点型数据如果成功,则值赋给变量grade,cin为真;当输入“Z”时,无法提取为浮点型,cin为假返回0,则程序结束。运行结果如下图:
一、用于字符输入的流成员函数
除了可以用cin输入标准类型的数据外,还可以用istream类流对象的一些成员函数,实现字符输入。
1.1 用get函数读取一个字符
流成员函数get有3种形式:无参数的,有一个参数的,有3个参数的。
(1)不带参数的get函数
调用形式为:
cin.get()
用来从指定的输入流提取一个字符(包括空白字符),函数的返回值是读入的字符。若遇到输入流中的文件结束符,则函数值返回文件结束标志EOF(End Of File),一般以-1代表EOF,用-1而不用0或正值,是考虑不与字符的ASCII代码混淆,但不同的C++系统所用的EOF值有可能不同。
使用get读取字符,示例如下:
#include <iostream>
using namespace std;
int main(){
int c;
cout <<"Enter Message:" <<endl;
while((c = cin.get()) != EOF) cout.put(c);
return 0;
}
按住Ctrl+Z后,再按Enter回车结束程序,运行后结果如下图:
C语言中的getchar函数与流成员函数cin.get()的功能相同,C++程序保留了C的这种用法,可以用getchar()从键盘读取一个字符赋给变量c。修改后代码如下:
#include <iostream>
using namespace std;
int main(){
int c;
cout <<"Enter Message:" <<endl;
while((c = getchar()) != EOF) cout.put(c);
return 0;
}
其运行结束和之前是一样的。
(2)有一个参数的get函数
调用形式为:
cin.get(ch)
其作用是从输入流中读取一个字符,赋给字符变量ch。如果读取成功则函数返回非0值(真),如失败(遇文件结束符)则函数返回0值(假)。
示例代码如下:
#include <iostream>
using namespace std;
int main(){
char c;
cout <<"Enter Message:" <<endl;
// 读取一个字符赋给字符变量c,如果读取成功,cin.get(c)为真
while(cin.get(c)) cout.put(c);
return 0;
}
运行结果如下图:
(3)有3个参数的get函数
调用 形式为:
cin.get(字符数组, 字符个数n, 终止字符)
或者
cin.get(字符指针, 字符个数n, 终止字符)
其作用是从输入流中读取n-1个字符,赋给指定的字符数组(或字符指针指向的数组),如果在读取n-1个字符之前遇到指定的终止字符,则提前结束读取。如果读取成功则函数返回非0值(真),如失败(遇文件结束符)则函数返回0值(假)。
示例代码如下:
#include <iostream>
using namespace std;
int main(){
char ch[20];
cout <<"Enter Message:" <<endl;
cin.get(ch, 15, '\n'); // 指定换行符为终止字符
cout <<ch <<endl;
return 0;
}
运行结果如下图:
此时,当输入完“I study C++ very hard.”后,按Enter回车则程序结束,最后输出结果为“I study C++ ve”原因是cin.get中指定字符个数为15。
1.2 用成员函数getline函数读入一行字符
cin.getline函数的作用是从输入流中读取一行字符,其用法与带3个参数的get函数类似。其调用形式为:
cin.getline(字符数组(或字符指针), 字符个数n, 终止标志字符)
示例代码如下:
#include <iostream>
using namespace std;
int main(){
char ch[20];
cout <<"Please enter all message:" <<endl;
// 注意:流提取符">>"从流中提取数据时通常跳过输入流中的空格、tab键、换行符等空白字符
cin >>ch;
cout <<"The string read with cin is:" <<ch <<endl <<endl; // 输出为I
/**
* getline读取时指针已移至后面"I"的空格位置
* 此时getline指定结束位置为'/',估计遇到终止符位置停止读取
*/
cin.getline(ch, 20, '/');
cout <<"The first message is:" <<ch <<endl;
cin.getline(ch, 20, '/');
cout <<"The second message is:" <<ch <<endl;
cin.getline(ch, 20);
cout <<"The third message is:" <<ch <<endl;
cout <<"End." <<endl;
return 0;
}
运行结果如下图:
如上图可见,“I like C++.”并未完整输出出来,这是因为cin>>读取字符串时,它会读取直到遇到空白字符(空格、制表符、换行符等)为止。因此,cin >> ch只会读取“I”,并将剩余的输入留在输入流(stdin)中。
接下来,使用了cin.getline()来尝试从输入流中读取数据,但第一次调用 cin.getline(ch, 20, '/')时,由于输入流中紧接着“I" 之后的就是空格和"like C++.",它会立即读取空格之后的内容(直到遇到换行符或达到指定的20个字符长度,或遇到指定的分隔符"/"),所以The first message对应的则是” like C++“。
要修复这个问题并读取完整的消息,应该使用getline()而不是cin >>,代码如下:
#include <iostream>
using namespace std;
int main(){
char ch[20];
cout <<"Please enter all message:" <<endl;
cin.getline(ch, 20, '/');
cout <<"The first message is:" <<ch <<endl;
cin.getline(ch, 20, '/');
cout <<"The second message is:" <<ch <<endl;
cin.getline(ch, 20);
cout <<"The third message is:" <<ch <<endl;
cout <<"End." <<endl;
return 0;
}
运行结果如下图:
二、istream类的其他成员函数
除了以上介绍的用于读取数据的成员函数外,istream类还有其他在输入数据时用的一些成员函数。
1.eof函数
eof是end of file的缩写,表示”文件结束“。从输入流读取数据,如果到达文件末尾(遇文件结束符),eof函数值为非零值(表示真),否则为0(假)。
示例代码如下:
#include <iostream>
using namespace std;
int main(){
char c;
cout <<"Please enter all message:" <<endl;
while( !(cin.eof()) ) if((c = cin.get()) != ' ') cout.put(c);
cout <<"End." <<endl;
return 0;
}
运行结果如下图:
2.peek函数
peek是”观察“的意思,peek函数的作用是观测下一个字符。调用形式为:
c = cin.peek();
cin.peek函数的返回值是指针指向的当前字符,但它只是观测,指针仍停留在当前位置,并不后移。如果要访问的字符是文件结束符,则函数值是EOF(-1)。
这里将1.2中示例代码修改下,使用循环输出内容。代码如下:
#include <iostream>
using namespace std;
int main(){
char c; // 接受peek()返回值
char ch[20];
int count= 0; // 记录索引值
cout <<"Please enter all message:" <<endl;
while((c = cin.peek()) == 'I'){
count++;
cin.getline(ch, 20, '/'); //读取字符
cout <<"The " <<count <<" message is:" <<ch <<endl;
}
cout <<"End." <<endl;
return 0;
}
cin.peek函数它用于检查输入流的下一个字符,但不会从流中移除该字符。这里cin.peek() == 'I' 表达式,用于检查输入流中的下一个字符是否是字符”I“。
刚好输入内容”I like C++./I study C++./I am happy./“中每行开始都以I为首字母,因此确保了执行循环时,每次输入都以I字母开头,当首字母不是"I"后则结束循环,结果如下图:
3.putback函数
调用形式:
cin.putback(ch);
其作用是将前面用get或getline函数从输入流中读取的字符ch返回到输入流,插入到当前指针位置,以供后面读取。
在1.2示例中,使用cin >>读取字符串时,它会读取到空字符为止,导致”I like C++“输出不完整。这里可以使用putback函数将字符返回到输入流中,代码如下:
#include <iostream>
using namespace std;
int main(){
char ch[20];
cout <<"Please enter all message:" <<endl;
cin >>ch; // 注意:流提取符">>"从流中提取数据时通常跳过输入流中的空格、tab键、换行符等空白字符
cout <<"The string read with cin is:" <<ch <<endl <<endl; // 输出为I
// 将I字符返回到输入流中
cin.putback(ch[0]);
/**
* getline读取时指针已移至后面"I"的空格位置
* 此时getline指定结束位置为'/',估计遇到终止符位置停止读取
*/
cin.getline(ch, 20, '/');
cout <<"The first message is:" <<ch <<endl;
cin.getline(ch, 20, '/');
cout <<"The second message is:" <<ch <<endl;
cin.getline(ch, 20);
cout <<"The third message is:" <<ch <<endl;
cout <<"End." <<endl;
return 0;
}
运行结果如下图:
4.ignore函数
调用形式为:
cin.ignore(n, 终止字符);
其作用是跳过输入流中n个字符,或在遇到指定的终止字符时提前结束(此时跳过包括终止字符在内有若干字符)。
示例1:
// 跳过输入流中5个字符,遇到'A'后就不再跳过
cin.ignore(5, 'A');
示例2:
// n默认值为1,终止字符默认为EOF
cin.ignore();
当前先通过一个示例,并查看运行后的结果,代码如下:
#include <iostream>
using namespace std;
int main(){
char ch[20];
int count= 0; // 记录索引值
cout <<"Please enter all message:" <<endl;
while(cin.peek() == 'I'){
count++;
cin.get(ch, 20, '/'); //读取字符
cout <<"The " <<count <<" message is:" <<ch <<endl;
}
cout <<"End." <<endl;
return 0;
}
运行结果如下图:
如上图可见,后面内容并未正常输出,这是遇到第一个字符的终止标志字符'/',读入结束。如果希望输出"I study C++”,则应该设法跳过输入流中第一个'/'(终止标志字符),可以使用ignore函数来实现这目的。代码如下:
#include <iostream>
using namespace std;
int main(){
char ch[20];
int count= 0; // 记录索引值
cout <<"Please enter all message:" <<endl;
while(cin.peek() == 'I'){
count++;
cin.get(ch, 20, '/'); //读取字符
cout <<"The " <<count <<" message is:" <<ch <<endl;
cin.ignore();
}
cout <<"End." <<endl;
return 0;
}
运行后结果如下图: