<iostream> 库功能庞杂,本节仅介绍最常用的部分。下面围绕输入类 istream 展开说明。
提取运算符(>>)
如前面课程所示,可使用提取运算符(>>)从输入流读取数据。C++ 为所有内置类型预定义了提取操作,也可为自己的类重载该运算符。
用提取运算符读入字符串时,常遇到缓冲区溢出问题:
char buf[10]{};
std::cin >> buf;
若用户输入 18 个字符,缓冲区将溢出,导致未定义行为。一般而言,绝不要假设用户会输入多少字符。
一种解决方法是使用操控符(manipulator)。操控符是可与 >> 或 << 联用以修改流行为的对象。你已使用过 std::endl,它既输出换行又刷新缓冲区。C++ 提供 setw(位于 <iomanip>)可限制读取字符数:
#include <iomanip>
char buf[10]{};
std::cin >> std::setw(10) >> buf;
此时最多读取 9 个字符(留一个给终止符),其余字符留在流中,等待下一次提取。
提取与空白符
再次提醒:提取运算符会跳过空白符(空格、制表符、换行)。
示例程序:
int main()
{
char ch{};
while (std::cin >> ch)
std::cout << ch;
return 0;
}
输入:
Hello my name is Alex
输出:
HellomynameisAlex
若想保留空白符,可使用 istream 提供的成员函数,其中最常用的是 get():
int main()
{
char ch{};
while (std::cin.get(ch))
std::cout << ch;
return 0;
}
输入同上,输出:
Hello my name is Alex
get() 还有字符串版本,可指定最大读取字符数:
int main()
{
char strBuf[11]{};
std::cin.get(strBuf, 11);
std::cout << strBuf << '\n';
return 0;
}
输入:
Hello my name is Alex
输出:
Hello my n
仅读取前 10 个字符,其余字符留在流中。
注意:get() 不会读取换行符。这可能导致意外结果:
int main()
{
char strBuf[11]{};
std::cin.get(strBuf, 11); // 读取至多 10 字符
std::cout << strBuf << '\n';
std::cin.get(strBuf, 11); // 再读取至多 10 字符
std::cout << strBuf << '\n';
return 0;
}
输入:
Hello!
输出:
Hello!
随后程序结束。原因是第一次 get() 读到换行即停止,第二次 get() 看到换行也立即返回,未再读取。
因此,可使用 getline(),它与 get() 类似,但会读取并丢弃分隔符(换行):
int main()
{
char strBuf[11]{};
std::cin.getline(strBuf, 11);
std::cout << strBuf << '\n';
std::cin.getline(strBuf, 11);
std::cout << strBuf << '\n';
return 0;
}
此代码行为符合预期,即使输入中含换行。
若需知道 getline() 上次读取了多少字符,可使用 gcount():
int main()
{
char strBuf[100]{};
std::cin.getline(strBuf, 100);
std::cout << strBuf << '\n';
std::cout << std::cin.gcount() << " characters were read" << '\n';
return 0;
}
gcount() 包含被提取且丢弃的分隔符。
std::string 专属 getline()
头文件 <string> 提供了非成员 getline(),用于读取 std::string:
#include <string>
#include <iostream>
int main()
{
std::string strBuf{};
std::getline(std::cin, strBuf);
std::cout << strBuf << '\n';
return 0;
}
更多有用的 istream 函数
ignore():丢弃流中第一个字符。ignore(int nCount):丢弃前nCount个字符。peek():预览下一个字符但不提取。unget():将最后读取的字符放回流中,供下次读取。putback(char ch):将指定字符放回流中,供下次读取。
istream 还包含许多其他函数及其变体,具体需求可查阅参考网站,如 cppreference.com。
