目录

使用 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 输出 

cout 与 << 运算符

cout 基本类型

cout 重载的 << 可识别 c++ 中所有基本类型,对于其每一种基本类型, ostream类都重载了 << 运算符。重载原型为 ostream& operator<< (  基本类型 ) ;注意其中重载的返回值是 ostream 类的引用,所以我们可以将输出连接起来,形象的就可以理解为数据一个接一个的流向 ostream。

cout 指针

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 <<endl; //这将输出 str 的地址

cout 拼接输出

前面我们说到了,插入运算符返回的是 ostream 类的引用因此可以做到拼接输出。

具体过程见下图(依次将str,12,’s' 拼接):

 cout 与 put()

原型: 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

cout 与 write()

模板原型:basic_ostream<char T, traits>& write (const char_type* s, streamsize n); 

第一个参数提供要显示的字符串的地址,第二个参数提供要显示的字符数,返回引用意味着可以拼接。但它有一个缺点:write 没有办法判定字符串是否结束,所以就算是越界也仍然会打印!!! 

write也可以打印数值,当你将数值的地址强制转为 char* 类型后传给 write ,但这样子大概率会出现乱码。

使用 cout 格式化输出

cout 输出时会把所有数据类型转换为文本格式输出,在默认情况下,char类型、整形、字符串,浮点型会显示在刚好容纳其本身的字段宽度中。而对于浮点型来说,默认会显示 6 位,末尾的 0 不显示。

setf() / unsetf() 函数总结与实例

接下来的 fmtflags 是一种 bitmask 类型用于存储格式标记,它的每一位都可以单独访问,且都有自己的含义,简单一点可以当作 int 整形来看(问题不大)。这个名称是在 ios_base 类中定义的,因此使用下面的常量时需要加上作用域解析符( :: )。

 原型一:fmtflags setf ( fmtflags )

常量含义
ios_base::boolalphabool 值显示为 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 << "默认情况下:" <<endl; 
	cout << "booltest: " << bool_test << endl 
		 << "int_test: " << int_test << endl
		 << "double_test: " << double_test <<endl << endl;
		 
	cout << "设置 ios_base::boolalpha:" << endl;
	cout.setf(ios_base::boolalpha);
	cout << "booltest: " << bool_test << endl << endl;
	
	cout << "设置 ios_base::showpoint:" << endl;
	cout.setf(ios_base::showpoint);
	cout << "double_test: " << double_test << endl << endl;
	
	cout << "设置 ios_base::showpos:" << endl;
	cout.setf(ios_base::showpos);
	cout << "int_test: " << int_test << endl
		 << "double_test: " << double_test << endl << endl;
		 
	cout << "设置 hex:" << endl;
	cout << hex;
	cout << "int_test: " << int_test << endl;
	cout << "设置 ios_base::uppercase:" << endl;
	cout.setf(ios_base::uppercase);
	cout << "int_test: " <<int_test << endl;
	cout << "设置 ios_base::showbase:" << endl;
	cout.setf(ios_base::showbase);
	cout << "int_test: " << int_test << endl << endl;
	
}

 原型二:fmtflags setf( fmtflags , fmtflags )

接收两个参数并返回以前的设置。第一个参数包含了所需设置的fmtflags值,第二个参数指出要清除第一个参数中的哪些位。(清除的目的是保证不会出现无效的设置情况,比如先后设置了使用基数8和使用基数10,如果不清除原来的设置,那基数8和基数10就会被同时设置,这是不被允许的!)

第一个参数第二个参数含义
ios_base:: decios_base:: basefield使用基数10
ios_base:: oct使用基数8
ios_base:: hex使用基数16
ios_base:: fixedios_base:: floatfield使用定点计数法
ios_base:: scientific使用科学计数法
ios_base:: leftios_base:: adjustfield使用左对齐
ios_base:: right使用右对齐
ios_base:: internal前缀(符号or基数)左对齐,数值右对齐

使用实例(这里只演示对齐方式,基数相关的与第一种没有太大差别,浮点数相关后面会细说):

int main(){
	
	double double_test = -6;
	
	cout << "默认情况下 (设置位宽为 8 ):" <<endl; 
	cout.width(8);
	cout << double_test <<endl << endl;
		 
	cout << "设置 ios_base::left + ios_base::adjustfield :" << endl;
	cout.setf(ios_base::left, ios_base::adjustfield);
	cout.width(8);
	cout << double_test <<endl << endl;
	
	cout << "设置 ios_base::right + ios_base::adjustfield :" << endl;
	cout.setf(ios_base::right, ios_base::adjustfield);
	cout.width(8);
	cout << double_test <<endl << endl;
		 
	cout << "设置 ios_base::internal + ios_base::adjustfield :" << endl;
	cout.setf(ios_base::internal, ios_base::adjustfield);
	cout.width(8);
	cout << double_test <<endl << endl;
	
}

unsetf()的使用

unsetf() 函数使用方法与 setf() 使用差别不大,只是 setf() 逆设置。

修改布尔值显示方式

布尔值在默认情况下会显示为 0 或 1 ,通过设置可以显示 true 或 false

  1. 使用 boolalpha / noboolalpha 控制符,例如:boolalpha(cout),将 cout 设置为显示 true 或 false。也可以直接 cout  << boolalpha ,这样子更加简洁且可以与其他输出拼接。
  2. 调用 setf() / unsetf() 函数,实际上第一种方法就是对 setf() 的调用。

修改显示时的进制

  1. 使用 dec, hex, oct 控制符,这些控制符本身是函数,所以可以如此调用:hex(cout) 将 cout 的进制改为十六。但更为常用的方法是使用重载了的插入运算符,如此:cout << hex; 这两种方法是等价的。
  2. 调用 setf() / unsetf() 函数, 实际上第一种方法就是对 setf() 的调用。

修改显示前缀

        进制前缀

  1. 使用 showbase / noshowbase 控制符,例如:showbase(cout),将 cout 设置为显示进制前缀,例如:假设当前设置为了16进制显示,设置进制前缀显示后,ff 将显示为 0xff。当然也可以如此调用: cout << showbase
  2. 调用 setf() / unsetf() 函数,实际上第一种方法就是对 setf() 的调用。

        符号前缀

  1. 使用 showpos / noshowpos 控制符,例如:showpos(cout),将 cout 设置为显示符号前缀(也可以说是正数是否显示正号),设置后,16 将会显示为 +16。当然也可以 cout<<showpos
  2. 调用 setf() / unsetf() 函数,实际上第一种方法就是对 setf() 的调用。

修改十六进制显示时的大小写

  1. 使用 uppercase / nouppercase 控制符,同样是两种方式都可以: uppercase(cout) 和  cout<<uppercase。设置 uppercase 后,十六进制数字 ff 将显示为 FF。
  2. 调用 setf() / unsetf() 函数,实际上第一种方法就是对 setf() 的调用。

修改字段宽度

  1. 使用 width() 方法。它有两种重载,其一是 int width(); 返回当前字段宽度,int width( int n); 设置当前字段宽度为 n 并返回之前的字段宽度。width()只会影响接下来显示的一个项目,然后字段宽度又会自动回到默认值。 
  2. 使用头文件 iomanip 中的 setw(int),拼接到 cout 中。例如:cout << setw(5) << 8 << endl;将以 5 位宽默认右对齐方式显示8。同样只设置接下来的一个项目

设置对齐方式

设置字段宽度后,对齐方式有三种:左对齐(left),右对齐(right),前缀左对齐后缀右对齐(internal)

  1. 使用 left / right / internal 控制符,同样是两种方式都可以:left(cout) 和 cout<<left。
  2. 调用 setf() / unsetf() 函数,实际上第一种方法就是对 setf() 的调用。

设置填充字符

默认情况下,cout使用空格来填充字段中未被使用的部分。

  1. 使用 fill() 方法。void fill( char t ) 将填充字符设置为 t 。例如:cout.fill( ' * ' ); 将填充字符设置为 ' * ' 号。此方法设置后一直有效,直到重新设置。 
  2. 使用头文件 iomanip 中的 setfill(char),拼接到 cout 中,例如:cout << setfill('*') << setw(8) << 5 <<endl; 将显示 *******5 。

设置浮点数显示模式

浮点数三种模式:默认模式,定点数模式(1.2,6.66等),科学计数模式(1.2e+6,5.4e-4等)

对于浮点数的显示模式,默认模式没有专门的控制符。

  1. 使用 fixed / scientific 控制符分别设置为定点模式,科学计数模式,特别注意默认模式的设置只能调用setf() 函数。控制符有两种使用方法:fixed(cout) 和 cout<<fixed
  2. 使用 setf() 函数,实际上第一种方法就是对 setf() 的调用。

首先我们要知道,以上及接下来所说的各种设置都是通过设置不同的位(一位就可以想成是一个开关有 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); 也可设置为默认模式,且这种方法是更好的选择。

以上三种方法首选第三种!

设置浮点数显示精度

      浮点数三种模式下精度含义:

                默认模式:显示的总位数

                定点数模式:小数点后的位数

                科学计数模式:小数点后的位数(指数位数取决于实现,不能设置 )

  1. 使用 precision() 方法,precision( int n ) 将精度设置为 n ,例如:cout.precision(8) 将浮点数精度设置为 8。一旦设置将一直有效,直到下一次更改。
  2. 使用头文件 iomanip 中的 setprecision(int),使用时拼接在 cout 中,例如:cout << fixed << setprecision(3) << 6.6 << endl; 将显示 6.600。而在默认模式下不显示后缀0,cout << setprecision(3) << 6.6 <<endl; 将显示 6.6。

显示末尾的 0 和小数点

显示时会根据当前精度来显示,例如默认情况下小数会显示 6 位,所以设置后 2 会显示为 2.00000 。这样会使得在某些情况下更加美观。

在定点表示法和科学表示法下,末尾的 0 会显示。

  1. 调用 setf() 函数,详情见 setf() 函数。

夹带私货之我对于setf()的理解

在不经意间我尝试 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 会写这么多##

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐