1. 流的四种状态是什么?什么情况下会进入到这种状态?
在C++中,流的状态由 ios_base 类中的状态标志位表示,共有四种:
- goodbit (good):值为0,表示流处于正常状态,一切操作准备就绪。
- 触发条件:默认状态或发生错误并成功清除错误后。
- eofbit (eof):表示到达了文件末尾(End of File)。
- 触发条件:读取操作尝试读取超出文件末尾的数据时(如
getline或>>读到文件最后)。
- 触发条件:读取操作尝试读取超出文件末尾的数据时(如
- failbit (fail):表示I/O操作失败,通常是逻辑上的错误,流还可以继续使用。
- 触发条件:类型匹配错误(例如试图将字母读入一个
int变量),或者打开文件失败。注意:读到文件末尾时也会同时设置 eofbit 和 failbit。
- 触发条件:类型匹配错误(例如试图将字母读入一个
- badbit (bad):表示流发生了严重的底层错误(如硬件错误、内存分配失败或写入只读文件),流通常已无法继续使用。
- 触发条件:物理I/O错误,例如磁盘已满或设备故障。
(注:可以通过 cin.good(), cin.eof(), cin.fail(), cin.bad() 来检测状态,使用 cin.clear() 来重置状态。)
2. cout的本质是什么?
cout 的本质是一个 全局的 std::ostream 类的对象(具体是 std::basic_ostream<char> 的派生类 std::ostream 的实例)。
- 它定义在
<iostream>头文件中。 - 它代表“标准输出设备”(通常是控制台/终端)。
- 它被设计为将数据格式化后插入到标准输出流中(通常使用
<<运算符重定向到标准输出,底层通过缓冲区刷新到屏幕)。
3. cin的本质是什么?
cin 的本质是一个 全局的 std::istream 类的对象(具体是 std::basic_istream<char> 的派生类 std::istream 的实例)。
- 它同样定义在
<iostream>头文件中。 - 它代表“标准输入设备”(通常是键盘)。
- 它负责从标准输入流中提取数据(通常使用
>>运算符,或者get(),getline()等函数)。
4. 什么是全缓冲?什么是行缓冲?
这是指I/O流底层的缓冲区策略,主要为了减少频繁的系统调用,提高效率。
- 全缓冲(Full Buffering):只有当缓冲区被填满时,才会执行实际的I/O系统调用(写入设备或从设备读取)。典型代表是磁盘文件读写(
fstream)。如果程序崩溃,缓冲区里未满的数据可能会丢失。 - 行缓冲(Line Buffering):当遇到换行符
\n时,或者缓冲区满时,就会执行实际的I/O操作。典型代表是终端上的cin和cout。这样做是为了让用户能及时看到输出(比如打印一行日志)。标准错误流cerr通常是无缓冲的。
5. 如何读取文件中的数据?有哪些方式?
首先需要包含头文件 <fstream>,并创建 ifstream(输入文件流)对象。
主要方式有:
- 使用流提取运算符
>>:适用于格式化数据(如整数、浮点数、以空格分隔的字符串)。file >> var; - 使用
getline()函数:读取整行数据(直到遇到换行符或指定分隔符)。std::getline(file, str); - 使用
get()函数:读取单个字符,可以读取包含空格在内的所有字符。char ch = file.get(); - 使用
read()函数:用于读取二进制数据。file.read(buffer, size); - 使用迭代器或
std::copy:搭配istreambuf_iterator遍历读取。
6. 如何向文件中写入数据?有哪些方式?
需要包含 <fstream>,并创建 ofstream(输出文件流)对象。打开时可以指定模式如 ios::out(默认,覆盖)、ios::app(追加)、ios::binary(二进制)。
主要方式有:
- 使用流插入运算符
<<:格式化写入,方便写入文本。file << "Hello" << 123 << endl; - 使用
put()函数:写入单个字符。file.put('A'); - 使用
write()函数:用于写入二进制数据。file.write(buffer, size); - 使用
std::copy搭配ostream_iterator:将容器中的数据直接写入文件。
7. 字符串流stringstream有什么作用?
stringstream 是 <sstream> 头文件中提供的类(包括 istringstream、ostringstream 和 stringstream),它的作用是在内存中操作字符串,将字符串当作流来处理。主要作用包括:
- 数据类型转换:无需使用
sprintf或atoi。可以轻松实现int转string,或者string转int/double。例如:stringstream ss; ss << 123; string str = ss.str(); // int转string - 字符串分割与解析:可以像读取
cin一样,利用>>运算符自动按空格分割字符串。 - 格式化拼接:将多个不同类型的变量拼接成一个复杂的字符串,比字符串加法更灵活,尤其适合格式化输出。
- 清空流:注意
ss.clear()清空状态,ss.str("")清空内容。