使用istream处理输入
本节阅读量:iostream库相当复杂——因此我们无法在这些教程中完整介绍它。这里会向您展示最常用的功能。在本节中,我们将研究输入类(istream)的各个方面。
提取运算符
在许多课程中都可以看到,可以使用提取运算符(»)从输入流中读取信息。C++为所有内置数据类型预定义了提取操作,并且之前我们也介绍了如何为自定义类重载提取运算符。
读取字符串时,提取运算符的一个常见问题是如何防止输入溢出缓冲区。以下示例:
|
|
如果用户输入18个字符会怎么样?缓冲区会溢出,导致不可预期的行为。一般来说,假设用户一定会按预期格式输入字符是有问题的。
处理此问题的一种方法是使用操纵器。操纵器是与提取(>>)或插入(<<)运算符一起使用、用于修改流行为的对象。您已经使用过的一个操纵器是“std::endl”,它既打印换行符,又清空缓冲区。C++提供了一个名为setw(位于iomanip头文件中)的操纵器,可用于限制从流中读入的字符数。要使用setw(),只需提供读取的最大字符数作为参数,并将其插入到输入语句中,如下所示:
|
|
该程序现在只会从流中读取前9个字符(为终止符留出空间)。任何剩余字符都会保留在流中,直到下一次提取。
提取和空白
提醒一下,提取运算符会跳过空白字符(空格、制表符和换行符)。
看看下面的程序:
|
|
当用户输入以下内容时:
|
|
提取运算符会跳过空格和换行符。因此,输出是:
|
|
通常,我们希望获取用户输入时,不应该丢弃空白字符。
为此,istream类提供了许多函数。最有用的一个是get()函数,它可以从输入流中获取原始字符。
下面是与上面相同的程序,使用get():
|
|
现在,当我们输入:
|
|
输出是:
|
|
还有一个字符串版本,它需要设置要读取的最大字符数量:
|
|
如果我们输入:
|
|
输出是:
|
|
注意,我们只读取前10个字符(必须为终止符保留一个字符)。其余字符留在输入流中。
关于get()需要注意的一件重要事情是,它不读取换行符!这可能会导致一些意外的结果:
|
|
如果用户输入:
|
|
程序将打印:
|
|
然后终止!它为什么不再多读取10个字符?答案是第一个get()读取到换行符后停止。第二个get()看到cin流中仍然有输入,并试图读取它。但第一个字符就是换行符,因此它立即停止。
因此,还有一个名为getline()的函数,它的工作方式类似于get(),但会提取(并丢弃)分隔符。
|
|
此代码将按预期执行,即使用户输入的字符串中包含换行符。
如果需要知道上次调用getline()提取了多少字符,请使用gcount():
|
|
gcount()包括任何提取和丢弃的分隔符。
用于std::string的getline()的特殊版本
getline()有一个特殊版本,位于istream类之外,用于将数据读取到std::string。这个特殊版本不是ostream或istream的成员,定义在string头文件中。下面是它的用法示例:
|
|
几个更有用的istream函数
还有几个您可能会用到的输入函数:
- ignore() 丢弃流中的第一个字符。
- ignore(int nCount) 丢弃前nCount字符。
- peek() 允许您从流中读取字符,而不将其从流中删除。
- unget() 将最后从流中读取的一个字符放回去,以便下次调用可以再次读取它。
- putback(char ch) 允许您将所选的字符放回流中,以便下一次调用读取。
istream包含许多其他函数,以及上述函数的变体。它们是否有用,取决于您需要执行的操作。您可以在这里找到对应文档。