前言:
C++是目前世界上性能最为强大的语言,虽然C++性能很强大,但是C++学习周期很长,那么,对于一些新手来说,最为困扰的就是C++的精度控制和一些格式转换问题
现在,让我们来看看C++的格式控制语法
(注1:以下所有代码均以使用using namespace std命名空间)
(注2:此文章参考于C++prime plus第六版)
1.将进制进行转换
ostream 类是从ios派生而来的,而ios则是从ios_base派生来的
ios_base类存储了描述格式状态信息,所以
很多的格式控制都需要ios_base类作为引导例如,
控制整数以十进制,十六进制,八进制显示,
可以使用dec,hex,oct控制符,如下:
int a=10;
cout<<a<<endl; //原型输出
cout<<dec<<a<<endl; //十进制输出a
cout<<hex<<a<<endl; //十六进制输出a
cout<<oct<<a<<endl; //八进制输出a
输出结果:
您可能以为cout<<dec(hex,oct)只有一次效果,那么下面的代码成功的说明了持续时间取决代码本是否对格式进行修改:
int b=100,a=10;
cout<<hex<<"a= "<<a<<endl; //十六进制输出a
cout<<"b = "<<b<<endl;
运行结果如下:
a是十六进制的a,十进制中的10,b是16进制的64,10进制的100
可以看到这种方法会影响后面的所有项目,除非您再次进行修改格式
2.修改字符宽度
使用width()可以修改字符的宽带,其方法原型如下:
int width();
int width(int i);
width(i)中,i是宽带的长度,当然width只能影响下一个项目,然后字符宽度将自动恢复为默认值如下代码:
cout<<'#';
cout.width(10);
cout<<10<<'#'<<50<<"#\n";
运行结果:
可以看到width只影响到了后一个项目
同时widt(i),i的参数可以是const 类型,也可以是#define类型
3.填充字符
fill()成员函数可以用来改变填充字符,例如:
cout.fill(’@’)
在某些情况下,这种填充方式会很受用
测试代码如下:
cout.fill('@'); //填充@字符
char *str[3]={"这里识别不出来","有几个","号"};
int num[3]={500,600,700};
for(int i=0;i<=2;i++) //3次循环
{
cout<<str[i]<<" :$"; //输出str的每个元素
cout.width(5);
cout<<num[i]<<endl; //输出num的每个元素
}
运行结果如下:
可以看到运行结果,width指定了5个宽度,
而数组num每一个字符只有3个宽度,
不满足5个,由于提前使用了cout.fill('@')进行填充,
所以前面的两位都变成了'@'
您可能对于char *str[3]={"这里识别不出来","有几个","号"};
这串代码有些不屑,当然本章只是对于C++的一些字符控制进行讲解
所以凡是由于使用VS等一些较新的编译器会带来报错提示,可能对您的心情有一定影响,请谅解
4.设置浮点数的显示精度
在一些老师布置的作业要求或者一些学校的OJ题目上,他们可能对于一些精度有着变态的要求,这通常会对C++学习者造成了困扰
precison是显示有效位的成员函数
原型如下:
int precison();
precison(int i);
其中i可以是const也可以是#define宏定义过的
测试代码如下:
float price1=10.45,price2=1.5+5.0/6.0;
cout<<"pricel = "<<price1<<endl; //正常格式
cout<<"price2 = "<<price2<<endl; //正常格式
cout.precision(4); //显示4位精度
cout<<" pricel = "<<price1<<endl; //只有4位有效,出现0会自动省略
cout<<" price2 = "<<price2<<endl; //只有4位,不会四舍五入
运行结果如下:
其中precsion函数会自动省略小数点后面的
5.打印末尾的0和小数点
ios_base提供了setf函数(用于set标记),能够控制多种格式化特性,此外ios_base函数提供了多个常量,可做setf函数的参数个数
如下面一行代码使cout显示末尾小数点
cout.setf(ios_base::showpoint);
当然,也会显示末尾位0的,测试代码如下:
float price1=10.40,price2=1.5+5.0/6.0;
cout<<"pricel = "<<price1<<endl; //正常格式
cout<<"price2 = "<<price2<<endl; //正常格式
cout.setf(ios_base::showpoint); //显示有所小数点
cout<<" pricel = "<<price1<<endl; //不会忽略0
cout<<" price2 = "<<price2<<endl;
运行结果:
可以看到通过setf函数输出了.
5.1 setf其他方法
setf有两种原型:
fmtflags setf(fmtlags);
fmtflags setf(fmtflags,fmtflags);
先来讲第一种:
fmtflags是bitmask类型的typedef名,用于存储格式标记,
该名称还是在ios_base类中定义的
bitmask类型是一种用来存储各个位置的类型,可以是整形,
枚举,甚至可以说是STL bitset容器
下表是fmtflag setf(fmtlags)的一些常量控制和格式控制
常量 | 含义 |
---|---|
ios_base::boolapha | 输出和输入bol值 |
ois_base::showpoint | 显示末尾小数点 |
ios_base::uppercase | 大写字母输出16进制 |
ios_base:showbase | 输出C++基数前缀 |
ios_base::showpos | 正数前面加上’+'号 |
测试其中几个函数,代码如下:
int s=20;
cout.setf(ios_base::showpos);
cout<<"s = "<<s<<endl; //已经填充'+'号
cout<<hex<<"s = "<<s<<endl; //16进制输出
cout.setf(ios_base::uppercase);
cout.setf(ios_base::showbase);
cout<<"s = "<<s<<endl; //以16进制输出,并输出前缀Ox
当然使用showpos,uppercase,showbase等都需要ios_base进行解析,而使用ios_base则需要编译指令或者编译声明
测试结果:
下面介绍第二种:
fmtlags setf(fmtflags,fmtflas);
和第一种不同的是,这种格式会返回以前的设置,第二种第一个参数和第一种一样,而第二种则需要清除指定第一个参数的那些位置
下面函数调用和16进制控制符作用相同
cout.setf(ios_base::hex,ios_base::basefield);
第一参数 | 第二参数 | 含义 |
---|---|---|
ios_base::dec | ios_base::basefield | 使用十进制基数 |
ios_base::oct | ios_base::basefield | 使用八进制基数 |
ios_base::hex | ios_base::basefield | 使用16进制基数 |
第一参数 | 第二参数 | 含义 |
---|---|---|
ios_base::fixed | ios_base::floatfield | 定点计数法 |
ios_base::scientifc | ios_base::floatfield | 使用科学计数法 |
ios_base::left | ios_base::adjustfield | 使用左对齐 |
ios_base::right | ios_base::adjustfield | 使用右对齐 |
ios_base::internal | ios_base::adjustfield | 符号或者基数前缀左对齐,值右对齐 |
根据上表,现在您是否能看懂如下代码:
ios_base::fmtflags old;
old=cout.setf(ios::left,ios::adjustfield);
如果想要回复以前的设置可以这样:
cout.setf(old,iso::adjustfield);
测试代码:
int main()
{
cout.setf(ios_base::left,ios_base::adjustfield);//左对齐
cout.setf(ios_base::showpos); //加上'+'号
cout.setf(ios_base::showpoint); //显示末尾小数
cout.precision(3); //显示3位有效位
ios_base::fmtflags old=cout.setf(ios_base::scientific,
ios_base::floatfield); //16进制控制符
cout<<"左对齐!"<<endl;
long n;
for(n=1;n<=40;n+=10)
{
cout.width(5); //显示4位
cout<<n<<"|";
cout.width(15);
cout<<sqrt(double(n))<<"|\n"; //开方
}
cout.setf(ios_base::internal,ios_base::adjustfield);
cout.setf(old,ios_base::floatfield); //消除基数前缀的左对齐,和值的右对齐
cout<<"去除科学表示法:\n";
for(n=1;n<=40;n+=10)
{
cout.width(5);
cout<<n<<"|";
cout.width(15);
cout<<sqrt(double(n))<<"|\n";
}
cout.setf(ios_base::right,ios_base::adjustfield);//右对齐
cout.setf(ios_base::fixed,ios_base::floatfield);//定点计数
cout<<"正确的结果:\n";
for(n=1;n<=40;n+=10)
{
cout.width(5);
cout<<n<<"|";
cout.width(15);
cout<<sqrt(double(n))<<"|\n";
}
return 0;
}
测试结果:
当然上面的代码想要运行别忘记了cmath头文件和iostream头文件
6.标准控制符表(参考)
控制符 | 引用 |
---|---|
boolalpha | setf(ios_base::boolalpha |
noboolalpha | unset(ios_base::noboolalpha) |
showbase | setf(ios_base::showbase |
noshowbase | nusetf(ios_::showbase |
showpoint | |
noshowpoint | unsetf(ios_base::showpoint |
showpos | setf(ios_base::showpos) |
noshowpos | unsetf(ios_base::showpos) |
uppercase | setf(ios_base::uppercase) |
nouppercase | unsetf(ios_base::uppercase) |
internal | setf(ios_base::internal,ios_base::adjustfield) |
fixed | setf(ios_base::fixed,ios_base::floatfield) |
scientific | setf(ios_base::scientific,ios_base::floatfield) |
如果系统支持则可以使用,否则继续使用setf();
当然,您可能注意到了标准控制符和前面的控制符差别所差无几,并且和一些英文单词几乎相同,所以都是便于学习者方便记住的