C/C++学习笔记十二 Input and Output (I/O)(2)

本文介绍C++中使用ostream和ios进行输出格式化的多种方法,包括设置标志和使用操纵器来控制输出格式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Output with ostream and ios

        istream 和 ostream 都派生自一个名为 ios 的类。 ios(和 ios_base)的工作之一是控制输出的格式化选项。

        有两种方法可以更改格式选项:标志和操纵器。 您可以将标志视为可以打开和关闭的布尔变量。 操纵器是放置在流中的对象,它们影响事物的输入和输出方式。

1、格式化

        要打开标志,请使用 setf() 函数,并将适当的标志作为参数。 例如,默认情况下,C++ 不会在正数前面打印 + 号。 但是,通过使用 std::ios::showpos 标志,我们可以改变这种行为:

std::cout.setf(std::ios::showpos); // turn on the std::ios::showpos flag
std::cout << 27 << '\n';

//输出
+27

        可以使用按位或 (|) 运算符一次打开多个 ios 标志:

std::cout.setf(std::ios::showpos | std::ios::uppercase); // turn on the std::ios::showpos and std::ios::uppercase flag
std::cout << 1234567.89f << '\n';

//输出
+1.23457E+06

        要关闭标志,请使用 unsetf() 函数:

std::cout.setf(std::ios::showpos); // turn on the std::ios::showpos flag
std::cout << 27 << '\n';
std::cout.unsetf(std::ios::showpos); // turn off the std::ios::showpos flag
std::cout << 28 << '\n';

//输出
+27
28

        使用 setf() 时还有一点需要提到的技巧。 许多标志属于组,称为格式组。 格式组是一组执行类似(有时互斥)格式选项的标志。 例如,名为“basefield”的格式组包含标志“oct”、“dec”和“hex”,它们控制整数值的基数。 默认情况下,设置了“dec”标志。 因此,如果我们这样做:

std::cout.setf(std::ios::hex); // try to turn on hex output
std::cout << 27 << '\n';

//输出
27

        它没有用! 原因是因为 setf() 只打开标志 - 关闭互斥标志还不够聪明。 因此,当我们打开 std::hex 时,std::ios::dec 仍然打开,并且 std::ios::dec 显然优先。 有两种方法可以解决这个问题。

        首先,我们可以关闭 std::ios::dec 以便只设置 std::hex :

std::cout.unsetf(std::ios::dec); // turn off decimal output
std::cout.setf(std::ios::hex); // turn on hexadecimal output
std::cout << 27 << '\n';

//输出
1b

        第二种方法是使用不同形式的 setf(),它接受两个参数:第一个参数是要设置的标志,第二个是它所属的格式化组。 当使用这种形式的 setf() 时,所有属于该组的标志都被关闭,只有传入的标志被打开。 例如:

std::cout.setf(std::ios::hex, std::ios::basefield);
std::cout << 27 << '\n';

//输出
1b

        使用 setf() 和 unsetf() 往往很尴尬,因此 C++ 提供了第二种更改格式选项的方法:操纵器。 操纵器的好处是它们足够聪明,可以打开和关闭适当的标志。 下面是一个使用一些操纵器来改变基础的例子:

std::cout << std::hex << 27 << '\n'; // print 27 in hex
std::cout << 28 << '\n'; // we're still in hex
std::cout << std::dec << 29 << '\n'; // back to decimal

//输出
1b
1c
29

        一般来说,使用操纵器比设置和取消设置标志要容易得多。 许多选项都可以通过标志和操纵器(例如更改基础)使用,但是,其他选项只能通过标志或操纵器使用,因此了解如何使用两者很重要。

2、更多的标志

(1)boolalpha

         代码参考

std::cout << true << " " << false << '\n';

std::cout.setf(std::ios::boolalpha);
std::cout << true << " " << false << '\n';

std::cout << std::noboolalpha << true << " " << false << '\n';

std::cout << std::boolalpha << true << " " << false << '\n';

//输出

1 0
true false
1 0
true false

(2)showpos 

         参考代码

std::cout << 5 << '\n';

std::cout.setf(std::ios::showpos);
std::cout << 5 << '\n';

std::cout << std::noshowpos << 5 << '\n';

std::cout << std::showpos << 5 << '\n';

//输出

5
+5
5
+5

(3)uppercase 

         参考代码

std::cout << 12345678.9 << '\n';

std::cout.setf(std::ios::uppercase);
std::cout << 12345678.9 << '\n';

std::cout << std::nouppercase << 12345678.9 << '\n';

std::cout << std::uppercase << 12345678.9 << '\n';

//输出

1.23457e+007
1.23457E+007
1.23457e+007
1.23457E+007

(4)显示不同进制 

std::cout << 27 << '\n';

std::cout.setf(std::ios::dec, std::ios::basefield);
std::cout << 27 << '\n';

std::cout.setf(std::ios::oct, std::ios::basefield);
std::cout << 27 << '\n';

std::cout.setf(std::ios::hex, std::ios::basefield);
std::cout << 27 << '\n';

std::cout << std::dec << 27 << '\n';
std::cout << std::oct << 27 << '\n';
std::cout << std::hex << 27 << '\n';

//输出

27
27
33
1b
27
33
1b

(5)精度、符号和小数点

        使用操纵器(或标志),可以更改显示浮点数的精度和格式。 有几种格式选项以某种复杂的方式组合在一起,因此我们将仔细研究一下。

        如果使用固定计数法或科学计数法,精度决定了分数中显示的小数位数。 请注意,如果精度小于有效位数,则该数字将被四舍五入。

std::cout << std::fixed << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

std::cout << std::scientific << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

//输出
123.456
123.4560
123.45600
123.456000
123.4560000

1.235e+002
1.2346e+002
1.23456e+002
1.234560e+002
1.2345600e+002

        如果既没有使用固定的也没有使用科学的,精度决定了应该显示多少有效数字。 同样,如果精度小于有效位数,则该数字将被四舍五入。

std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

//输出

123
123.5
123.46
123.456
123.456

        使用 showpoint 操纵器或标志,您可以使流写入小数点和尾随零。

std::cout << std::showpoint << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

//输出

123.
123.5
123.46
123.456
123.4560

        这是一个包含更多示例的汇总表:

 (6)宽度、填充字符和对齐

        通常,当您打印数字时,将打印数字而不考虑它们周围的空间。 但是,可以左对齐或右对齐数字的打印。 为了做到这一点,我们必须首先定义一个字段宽度,它定义了一个值将具有的输出空间的数量。 如果实际打印的数字小于字段宽度,它将左对齐或右对齐(如指定)。 如果实际数字大于字段宽度,则不会被截断——它会溢出字段。

        为了使用这些格式化程序中的任何一个,我们首先必须设置一个字段宽度。 这可以通过 width(int) 成员函数或 setw() 操纵器来完成。 请注意,右对齐是默认设置。

std::cout << -12345 << '\n'; // print default value with no field width
std::cout << std::setw(10) << -12345 << '\n'; // print default with field width
std::cout << std::setw(10) << std::left << -12345 << '\n'; // print left justified
std::cout << std::setw(10) << std::right << -12345 << '\n'; // print right justified
std::cout << std::setw(10) << std::internal << -12345 << '\n'; // print internally justified

//输出

-12345
    -12345
-12345
    -12345
-    12345

        需要注意的一点是 setw() 和 width() 只影响下一个输出语句。 它们不像其他一些标志/操纵器那样持久。

        现在,让我们设置一个填充字符并执行相同的示例:

std::cout.fill('*');
std::cout << -12345 << '\n'; // print default value with no field width
std::cout << std::setw(10) << -12345 << '\n'; // print default with field width
std::cout << std::setw(10) << std::left << -12345 << '\n'; // print left justified
std::cout << std::setw(10) << std::right << -12345 << '\n'; // print right justified
std::cout << std::setw(10) << std::internal << -12345 << '\n'; // print internally justified

//输出

-12345
****-12345
-12345****
****-12345
-****12345

        请注意,该字段中的所有空格都已用填充字符填充。

        ostream 类和 iostream 库包含其他可能有用的输出函数、标志和操纵器,具体取决于您需要执行的操作。 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坐望云起

如果觉得有用,请不吝打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值