16 IO
16.1 格式化IO
C++提供了两种格式控制的方法:一种方法是使用ios类中有关格式控制的成员函数;另一种方法是使用称为可是控制符的特殊类型的函数
16.1.1 用ios类的成员函数进行格式控制
ios类中有几个成员函数可以用来对输入输出进行格式控制,进行格式控制主要是通过对格式状态字,域宽,填充字符以及输出精度的操作来完成的。
16.1.2 格式状态字
输入输出格式由一个long int类型的格式状态字确定,状态字的各位都控制一定的输入输出特征,例如格式状态子的最右以为为1,则表示在输入时跳过空白字符。在ios类的public部分定义了一个枚举,它的每个成员可以跟别定义格式状态字的每一位。
enum{
skipws =0x0001, //输入时,跳过开头的空白字符(空格,制表,换行)
left =0x0002, //
right =0x0004, //
internal = 0x0008 //数值符号左对齐,数值右对齐
dec,oct,hex //10 8 16进制
showbase //显示“基指示符”如设置hex和showbase,则显示“0x”
showpoint //强制显示float和double型数据的小数点及后的无效0
uppercase //数值中的字母(指数符“e”.16禁制数字)大写显示
showpos //正数前加“+”
scientific fixed //scientific:浮点数科学计数法,fixed:浮点数常规
unitbuf //输出操作后立即刷新所有流,刷新流意味着把输出写到与流相连的设备
stdio //每次输出,刷新stdout和stderr
}
16.1.3 ios类中用于控制输入输出格式的成员函数
long ios::flags(); //返回当前格式状态字
long ios::flags(long); //设置格式状态字并返回
long ios::setf(long); //设置指定的标志位
long ios::unsetf(long); //清除指定的标志位
int ios::width(); //返回当前显示数据的域宽
int ios::width(int); //设置当前显示数据域宽并返回原域宽
char ios::fill(); //返回当前填充字符
char ios::fill(char); //设置填充字符并返回原填充字符
int ios::precision(); //返回当前浮点数的精度
int ios::precision(int); //设置浮点数精度并返回原精度
16.1.4 使用IO操作符进行格式控制
C++预定义的操作符分为带参数的操作符和不带参数的操作符。通常,不带参数的操作符在iostream文件中定义,而带参数的操作符在iomanip文件中定义。
#include<iostream>:
endl //输入时插入换行符并刷新流
ends //输出时在字符串后插入空字符(NULL)最为尾符
flush //刷新,把流从缓冲区输出到目标设备
ws //输入时略去空白字符
dec hex oct //10 16 8进制
#include<iomanip>:
setbase(int n) //设置转换基数为n(0,8,10,16),默认为0,表示10进制输出
resetiosflags(long f) //清除由参数f指定的标志位,用于输入输出
setiosflags(long f) //设置参数f指定的标志位
setfill(char c) //设置填充字符
setprecision(int n) //设置浮点数精度(默认6)
setw(int n) //设置数据宽度
#include<iostream>
#include<iomanip>
#include<string>
#include<typeinfo>
using namespace std;
int main()
{
//成员函数&格式状态字控制
cout << "当前默认状态字:"<< cout.flags() << endl;
cout.flags(ios::skipws|ios::left|ios::hex|ios::showbase|
ios::uppercase|ios::showpos|ios::unitbuf);
cout << "修改后状态字:"<< cout.flags() << dec << "(" << cout.flags()<< ")"<< endl;
cout.fill('#');
cout <<"输出数字65536:" << endl<<setw(8) << 65536 << endl;
cout << "设置填充和域宽:"<< endl;
cout.width(12); //只对下一句起作用
cout << 65536 << endl <<"注:填充不影响关键字,但保持有效性直到更改"<< endl;
cout << " 关键字一旦修改就不会自动恢复,区别于操作符控制"<< endl;
cout << "****************************" << endl;
//操作符格式控制
cout<< dec << 256 << endl << oct << 256 << endl << hex << 256 <<endl;
cout<< setw(15) << setfill('^') << setprecision(8) << 123.456789 << endl;
cout << endl;
return 0;
}
输出结果:
自定义输出格式:
#include<iostream>
using namespace std;
//方法一:无参:类-对象
class HexUpBas
{
public:
friend ostream& operator<<(ostream &o,const HexUpBas hub)
{
return o<< hex << uppercase << showbase ;
}
};
const HexUpBas hub = HexUpBas();
//方法二:有参 类
class wf
{
int w;
unsigned char fill;
public:
wf(int w, unsigned char f=' '):w(w),fill(f){}
friend ostream& operator<<(ostream& o,const wf& x) //临时对象
{
o.width(x.w);
o.fill(x.fill);
return o;
}
};
//方法三:函数
ostream& func(ostream& o)
{
return o<< dec << showpos;
}
// 工作原理:ostream类中
// ostream& operator<<(ostream& (*f)(ostream& o))
// { return f(*this); }
int main()
{
cout << hub << 12346<<endl;
cout << wf(10,'*') <<"hello"<< endl;
cout << func<< 589 << endl;
return 0;
}
16.2 控制台的输入输出
16.2.1格式化的输入输出
cout<< cin>>跳过空白字符,格式自动转换完成的,重载的<< >>来实现的
cerr 无缓冲,也不允许重定向
cout可缓冲,可重定向
clog理论上可缓冲,不可重定向,实际上无缓冲不可重定向
//输出缓冲区遇到换行、有输入、满、程序结束、flush会刷新
cout<<"hello";
cerr<<"world";
clog<<"tarena";
输出结果是cerr东西先出来,然后是clog,最后是cout
如果重定向的话a.out>file cat file结果只有cout的东西重定向了
16.2.2 非格式化的输入输出
.get()读取一个字符,类似C中getchar(),不会跳过空白字符
.put()写一个字符 //ostream& put( char ch );
.getline(char数组,数组大小) //如果不能读完一整行会设置错误状态
getline(i对象,string对象引用) //不是成员函数而是全局函数
这两个版本都可以添加第三个参数,指定结束字符,默认是读到换行,为读到什么字符为止
.ignore() //istream& ignore( int nCount = 1, int delim = EOF );
.putback()
.peek()查看输入缓冲区第一个字符
io对象要求能转换成bool类型,对处于正常状态的io对象转成true,对处于错误状态的io对象转成false
io对象如果正常就是真,错误为假,io对象如果处于错误状态就拒绝io,纠正办法是cin.clear()(清除错误状态,不清缓冲区)
string s;
s.c_str(); //转成C风格字符串
printf("%s\n",s.c_str());
#include<iostream>
using namespace std;
int main()
{
int i;
cout << "请输入一个数字:"<< endl;
cin >> i;
while(!cin)
{
cout << "输入错误字符!" << endl;
cin.clear();
cin.ignore(200,'\n');//cin.clear()重置了cin的状态,没有清空缓存
cin >> i; //cin.get()不会改变cin的状态,无论成功与否cin都是true
}
cout << "输入缓冲区中第一个字符:" << cin.peek() << endl; //查看缓冲区第一个字符(根据上面:回车)
cin.ignore(200,'\n');
cout << "cin.get()可以读取回车,制表,空格,区别于cin >> "<< endl;
cin.get(); //读取一个字符,可以当做程序停顿使用,并不忽略回车,制表,空格
cout <<"停顿完成!" << endl;
cout << "输入字符串以'*'结尾:" << endl;
char str[100];
cin.getline(str,100,'*');//最后一个参数为读到此字符为止,默认为'\n'
cout <<"查看字符串内容:" << str << endl;
char c;
cout <<"输入缓冲区中第一个字符:" << cin.peek() << endl;
c=cin.get();
cout<<"读取之后,输入缓冲区中第一个字符:" << cin.peek()<< endl;
cin.putback(c);
cout << "还回之后,输入缓冲区中第一个字符:" <<cin.peek()<<endl;
return 0;
}
输出结果: