目录
使用 cout 输出
cout 与 << 运算符
cout 基本类型
cout 指针
cout 拼接输出
cout 与 put()
cout 与 write()
使用 cout 格式化输出
setf() / unsetf() 函数总结与实例
原型一:fmtflags setf ( fmtflags )
原型二:fmtflags setf( fmtflags , fmtflags )
unsetf()的使用
修改布尔值显示方式
修改显示时的进制
修改显示前缀
进制前缀
符号前缀
修改十六进制显示时的大小写
修改字段宽度
设置对齐方式
设置填充字符
设置浮点数显示模式
设置浮点数显示精度
显示末尾的 0 和小数点
夹带私货之我对于setf()的理解
写在前面:关于c++的输入和输出平时学习的比较零碎,用的也比较少,所以总是经常忘记,趁此假期之余浅浅总结一下以备日后复习。【根据 c++ primer plus】
cout 重载的 << 可识别 c++ 中所有基本类型,对于其每一种基本类型, ostream类都重载了 << 运算符。重载原型为 ostream& operator<< ( 基本类型 ) ;注意其中重载的返回值是 ostream 类的引用,所以我们可以将输出连接起来,形象的就可以理解为数据一个接一个的流向 ostream。
ostream 类为 const signed char* , const unsigned char* , const char* , char* , void* 定义了插入运算符(<<)。这使得当 cout char系列的指针时,会输出对应的字符串。而cout void* 时则会输出地址的数值表示,因此如果我们想要打印char系列的地址而不是将该地址的字符串打印出来,就要将其转化为 void* 类型的指针。
例如:
char* str = "This is a string\n";
cout << str << endl; //这将输出 "This is a string\n" 这个字符串
cout << (void*)str <
前面我们说到了,插入运算符返回的是 ostream 类的引用因此可以做到拼接输出。
具体过程见下图(依次将str,12,’s' 拼接):
原型: ostream& put( char )
可以发现 put 返回的也是 ostream 类的引用,这就意味着它可以像插入运算符一样进行拼接输出 且每次输出一个字符。
例如:
cout.put('S').put('t').put('r').put('i').put('n').put('g');
这一句代码将输出字符串 "String"
当然也可以用对应的 数字(前提是有效地)输出字符
例如:
cout.put(65); //输出A
cout.put(66.6); //输出B
模板原型:basic_ostream
& write (const char_type* s, streamsize n);
第一个参数提供要显示的字符串的地址,第二个参数提供要显示的字符数,返回引用意味着可以拼接。但它有一个缺点:write 没有办法判定字符串是否结束,所以就算是越界也仍然会打印!!!
write也可以打印数值,当你将数值的地址强制转为 char* 类型后传给 write ,但这样子大概率会出现乱码。
cout 输出时会把所有数据类型转换为文本格式输出,在默认情况下,char类型、整形、字符串,浮点型会显示在刚好容纳其本身的字段宽度中。而对于浮点型来说,默认会显示 6 位,末尾的 0 不显示。
接下来的 fmtflags 是一种 bitmask 类型用于存储格式标记,它的每一位都可以单独访问,且都有自己的含义,简单一点可以当作 int 整形来看(问题不大)。这个名称是在 ios_base 类中定义的,因此使用下面的常量时需要加上作用域解析符( :: )。
常量 | 含义 |
ios_base::boolalpha | bool 值显示为 true 和 false |
ios_base::showbase | 输出时显示前缀(0,0x) |
ios_base::showpoint |
显示末尾小数点 |
ios_base::uppercase | 显示16进制时使用大写字母 |
ios_base::showpos | 显示符号,正数前加 + |
使用实例(在 std 命名空间下):
int main(){
bool bool_test = true;
int int_test = 1034;
double double_test = -6;
cout << "默认情况下:" <
接收两个参数并返回以前的设置。第一个参数包含了所需设置的fmtflags值,第二个参数指出要清除第一个参数中的哪些位。(清除的目的是保证不会出现无效的设置情况,比如先后设置了使用基数8和使用基数10,如果不清除原来的设置,那基数8和基数10就会被同时设置,这是不被允许的!)
第一个参数 | 第二个参数 | 含义 |
ios_base:: dec | ios_base:: basefield | 使用基数10 |
ios_base:: oct | 使用基数8 | |
ios_base:: hex | 使用基数16 | |
ios_base:: fixed | ios_base:: floatfield | 使用定点计数法 |
ios_base:: scientific | 使用科学计数法 | |
ios_base:: left | ios_base:: adjustfield | 使用左对齐 |
ios_base:: right | 使用右对齐 | |
ios_base:: internal | 前缀(符号or基数)左对齐,数值右对齐 |
使用实例(这里只演示对齐方式,基数相关的与第一种没有太大差别,浮点数相关后面会细说):
int main(){
double double_test = -6;
cout << "默认情况下 (设置位宽为 8 ):" <
unsetf() 函数使用方法与 setf() 使用差别不大,只是 setf() 逆设置。
布尔值在默认情况下会显示为 0 或 1 ,通过设置可以显示 true 或 false
在设置字段宽度后,对齐方式有三种:左对齐(left),右对齐(right),前缀左对齐后缀右对齐(internal)
默认情况下,cout使用空格来填充字段中未被使用的部分。
浮点数三种模式:默认模式,定点数模式(1.2,6.66等),科学计数模式(1.2e+6,5.4e-4等)
对于浮点数的显示模式,默认模式没有专门的控制符。
首先我们要知道,以上及接下来所说的各种设置都是通过设置不同的位(一位就可以想成是一个开关有 0 和 1 两种情况)是 1 还是 0 来设置模式的。这里打个比方,见下图:
这个时候,控制定点表示的开关关闭(0),控制科学表示的开关打开(1),即 01 就意味着当前浮点数显示方式为科学计数模式。
而当10时就说明当前浮点数表示方式为定点模式。 而当 00,11 时,这两种情况既不是定点也不是科学,那就使用默认情况。
所以启用默认模式的方式之一就是: cout.setf(0, ios_base::floatfield); 将两位设置为00。(这一种方法我在dev上行不通)
如果已知当前是 fixed 模式,那么可以调用 fixed 的 unsetf() 函数:cout.unsetf(fixed);
当不知道当前什么模式的时候,可以调用 floatfield 的 unsetf() 函数: cout.unsetf(ios_base::floatfield); 也可设置为默认模式,且这种方法是更好的选择。
以上三种方法首选第三种!
浮点数三种模式下精度含义:
默认模式:显示的总位数
定点数模式:小数点后的位数
科学计数模式:小数点后的位数(指数位数取决于实现,不能设置 )
显示时会根据当前精度来显示,例如默认情况下小数会显示 6 位,所以设置后 2 会显示为 2.00000 。这样会使得在某些情况下更加美观。
在定点表示法和科学表示法下,末尾的 0 会显示。
在不经意间我尝试 cout << ios _base::floatfield; 发现居然可以,输出的值是260!可能在某些地方可以查到相关的内容和,但自己试一试还是很有趣的。
首先列出每一个常量的二进制值(这里二进制数字位数取了最长的uppercase的整数16位):
floatfield: 0000 0001 0000 0100
basefield: 0000 0000 0100 1010
adjustfield:0000 0000 1011 0000
发现每一个 field 的 1 的位置都不一样,初步推断这些 1 就是存储对应信息的位
floatfield 中 fixed 是 0000 0000 0000 0100 ;scientific 是 0000 0001 0000 0000;
basefield中 dec是 0000 0000 0000 0010;oct是 00000 000 0100 0000;
hex是0000 0000 0000 1000;
adjustfield中 left是 0000 0000 0010 0000; right是0000 0000 1000 0000;
internal是0000 0000 0001 0000;
boolalpha是 0000 0000 0000 0001
showbase是 0000 0010 0000 0000
showpoint是 0000 0100 0000 0000
uppercase是 0100 0000 0000 0000
showpos是 0000 1000 0000 0000
现在对比就发现每一个控制符对应的位是哪一个。
画一个图清楚一点:
那么就可以得出一个结论: 假设这个存信息的变量叫 "格式变量" (随便起的名字),那么setf(fmtflags)就是把"格式变量"和fmtflags做位或运算,使得对应位是1,从而完成格式的设置。fmtflags setf(fmtflags1,fmtflags2) 就是先记录原来的"格式变量"用作返回值,然后用 fmtflags2 的位非 位与 "格式变量"完成原来对应 field 的格式清除,最后把"格式变量"和 fmtflags1 做位或运算完成格式设置。
那么unsetf(fmtflags) 就是把 fmtflags 位非 后 位与 "格式变量",使得对应位变为 0。
只不过 fmflags 没有定义方法进行位运算,也没有定义方法转换 int 为 fmtflads 等。所以以上这些都是我的猜测,但是这个猜测又能解释 setf(ios_base::floatfield) 可以完成浮点数默认计数模式的设置,因为同时把两位设置为了 1,出现了无效情况。还有我先setf(ios_base::floatfield) 再 unsetf(ios_base::scientific) 后会设置为 fixed 模式,因为我先设置了两位然后取消了一位,另一位对 fixed 的设置还是 1。(好像又没有什么问题...amazing啊!)。
##后续再写关于 cin 的内容吧,没有想到 cout 会写这么多##