写在前面:
说到流操作,则与程序的输入输出(简记为I/O)有关,本文讲述C++的一些I/O操作。本文所用的一些操作虽然都是基于标准输入输出(如屏幕和键盘到程序的输出和输入),但是这些规则对于接下来的文件操作也是有用的。C++ I/O 区分流的种类,特定种类的I/O只能处理特定数据类型的流,称作种类安全流机制(Type-safe IO)(Chap 13 13.1 p.g.416)
C++含有变量wchar_t,用来表示Unicode字符;char16_t和char32_t是分别限定Unicode大小的字符变量种类。(Chap 13 13.2 p.g.418)
几个常用的有关流操作的头文件: <iostream>:定义基本I/O对象,例如cin, cout, cerr(非缓冲流,立即被输出到输出设备)和clog <iomanip>:提供格式化流操作 <fstream>:用于文件处理的流操作(本章不涉及,在文件操作时会再提)
在流文件中,存在如下定义:
//在流编程中一般直接使用typedef定义的名称
typedef basic_istream<char> istream;
typedef basic_ostream<char> ostream;
typedef basic_iostream<char> iostream;
关于typedef参考: https://my.oschina.net/SamYjy/blog/912868
C++流结构图示如下:
关于void *的两个作用:
void *用于输出字符指针的地址
由于C++自动决定数据的类型,因此当碰到诸如输出char *的值(指针的值是地址)的情况时,就需要把指针转化为空指针再进行输出,例如:
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
const char *const words = "This is a sentence.";
int num = 7;
const int * const numPtr = #
//输出char*的值所对应的内容:
cout << "Content of words is: " << words << endl;
cout << "Content of numPtr is: " << *numPtr << endl;
//输出char*的值(是一个地址):
cout << "Value of words is: " << static_cast< const void * >( words ) << endl;
cout << "Value of numPtr is: " << numPtr << endl;
cout << "Value of numPtr is: " << static_cast< const void * >( numPtr ) << endl;
return 0;
}
- put方法:输出单个字符串,可以层叠,用法例如:
cout.put('A').put('\n').put('B');
void *被隐式调用用于判定输入是否结束:
此时,void *往往被cin.get()方法隐式调用,以判断输入是否完成。例如:
//EOF为cin.get()隐式调用void *之后文件结束的返回值
while ( ( character = cin.get() ) != EOF )
cout.put( character );
其中,cin.get有5个不同类型的版本。详细见参考资料相应部分。此方法默认输入不固定长度,并且以空格符号为界定符,将输入赋值给指定char *变量。使用举例如下:
#include <iostream>
using namespace std;
int main()
{
// create two char arrays, each with 80 elements
const int SIZE = 80;
char buffer1[ SIZE ];
char buffer2[ SIZE ];
char buffer3[ SIZE ];
// use cin to input characters into buffer1
cout << "Enter a sentence:" << endl;
cin >> buffer1;
// display buffer1 contents
cout << "\nBuffer 1:" << buffer1 << endl;
// use cin.get to input characters into buffer2
cin.get( buffer2, SIZE, 'l' );
//如果界定符前一个字符是r,将字母r放回流中
cin.putback('r');
// display buffer2 contents
cout << "Buffer 2:" << buffer2 << endl;
int nextChar = cin.peek();
cout << "Next char will be output is: " << (char)(nextChar) << endl;
/*使用如下两种方法可以清除流中不需要的多余数据:*/
//方法一:
//int input;
//while(input = cin.get() != '\n')
//By default, ignore method ignores 1 char only
//cin.ignore(1); //此处可以不写1
//方法二:
//fflush(stdin);
cin.get( buffer3, SIZE );
cout << "Buffer 3: " << buffer3 << endl;
} // end main
用于处理非格式化I/O的方法:read, write和gcount:
对于非格式化流,C++使用read函数向程序读入数据,使用write函数向输出(可能是屏幕或硬盘)写出数据,使用gcount统计上一个输入流的字符长度(输入不满char[] 大小时按实际输入长度确定)。举例如下:
#include <iostream>
using namespace std;
int main()
{
const int SIZE = 80;
char buffer[ SIZE ]; // create array of 80 characters
// use function read to input characters into buffer
cout << "Enter a sentence:" << endl;
cin.read( buffer, 20 );
cout << "Length of last in stream: " << cin.gcount() << endl;
// use functions write and gcount to display buffer characters
cout << endl << "The sentence entered was:" << endl;
cout.write( buffer, cin.gcount() );
cout << endl;
} // end main
流操作符简介
常用流函数:
- setbase(int):设置输出数据的基数,此整数可以为2,8,10或16
- setprecision(int) / cout.setprecision(int):设置输出小数的精度
- setw(int) / cout.width(int) / cin.width(int):设置输出/输入的字符最大长度,输出超过最大长度的,则按照字符长度输出整个字符;而输入则最多读入最大长度的字符。详细情况见以下示例程序。
- setfill(char) / cout.fill(char) :往往与setw搭配使用,在多余的空格处填充相应字符。
常用流操作常量一览:
示例程序:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int widthValue = 4;
char sentence[ 10 ];
cout << "Enter a sentence:" << endl;
cin.width( 6 ); // input only 5 characters from sentence
cout << setfill('*');
//or can be:
//cout.fill('*');
// set field width, then display characters based on that width
while ( cin >> sentence )
{
cout << setw(widthValue ++);
cout << sentence << endl;
cout << "Length of output: " << oct << showbase << widthValue << endl;
//Can also be:
//cout.width( widthValue++ );
cin.width(6);
//Or can be:
//cin >> setw( 6 ); // input 5 more characters from sentence
} // end while
} // end main
输出解释:cin默认情况相当于cin.get(),碰到界定符为空格时停止从流中读入数据,并将空格符号作为下一次读入的第一个字符。由于单词member前五个字母以及它之前一个空格正好构成6个字符,达到了输入流限制的最大长度,因此字母r作为下一个输入流的起始被读入。同理可分析function的读入情况。
C++中,可以通过在程序运行前储存程序当前流操作符号状态,使用完毕后恢复的方式来避免粘性流操作符对于之后程序产生的可能影响,具体程序如下:
//储存当前流操作符状态:
ios_base::fmtflags originalFormat = cout.flags();
//省略中间部分可能改变流操作符状态的部分
//......
//恢复到原来的流操作符状态:
cout.flags(originalFormat);
C++中,可以通过cin.clear()使得输入流恢复到一个正常流的状态,限于篇幅,这一点本文不展开,详见参考资料(C++11 Chap 13.8 p.g.442)
在C++中,标准输入流往往总是在其相应输出流之后出现,目的是便于向用户提供交互信息后再采纳用户输入。对于其他一般的流,则可以通过
input.tie(&output);
的方式指定相应流运行的顺序。取消这样的顺序限定,可以使用
input.tie(0);
实现。
参考资料:
- CppReference - get method, URL: http://en.cppreference.com/w/cpp/io/basic_istream/get
- CppReference: I/O Manipulator: http://en.cppreference.com/w/cpp/io/manip
- Paul Deitel & Harvey Deitel, C++11程序设计(英文版)(第2版),本文中C++11括号所表示的资料