首页 > 编程语言 >C++格式化输入和输出

C++格式化输入和输出

时间:2024-04-01 12:33:05浏览次数:14  
标签:输出 格式化 cout 打印 C++ 操纵 默认 格式 输入

格式化输入与输出

除了条件状态外,每个iostream对象还维护一个格式状态来控制IO如何格式化的细节。

格式状态控制格式化的某些方面,如整型值是几进制、浮点值的精度、一个输出元素的宽度等。

标准库定义了一组操纵符来修改流的格式状态。

一个操纵符是一个函数或是一个对象,会影响流的状态,并能用作输入或输出运算符的运算对象。类似输入和输出运算符,操纵符也返回它所处理的流对象,因此我们可以在一条语句中组合操纵符和数据。

我们已经在程序中使用过一个操纵符——endl,我们将它“写”到输出流,就像它是一个值一样。但endl不是一个普通值,而是一个操作:它输出一个换行符并刷新缓冲区。

很多操纵符改变格式状态

操纵符用于两大类输出控制;控制数值的输出形式以及控制补白的数量和位置。

大多数改变格式状态的操纵符都是设置/复原成对的;

一个操纵符用来将格式状态设置为一个新值,而另一个用来将其复原,恢复为正常的默认格式。

当操纵符改变流的格式状态时,通常改变后的状态对所有后续IO都生效

当我们有一组IO操作希望使用相同的格式时,操纵符对格式状态的改变是持久的这特性很有用。

实际上,一些程序会利用操纵符的这一特性对其所有输入或输出重置一个成多个格式规则的行为。在这种情况下,操纵符会改变流这一特性就是满足要求的了。

但是,很多程序(而且更重要的是,很多程序员)期望流的状态符合标准库正常的默认设置。在这些情况下,将流的状态置于一个非标准状态可能会导致错误。因此,通常最好在不再需要特殊格式时尽快将流恢复到默认状态。

控制整型格式

控制布尔值的格式

操纵符改变对象的格式状态的一个例子是 boolalpha 操纵符。

默认情况下,bool值打印为1或0。一个true值输出为整数1,而false输出为0,我们可以通过对流使用booialpha操纵符来覆盖这种格式:

cout << "default bool values: " << true << " " << false;
cout<< "\nalpha bool values: " << boolalpha<< true << " " << false << endl;


执行这段程序会得到下面的结果:

default bool values: 1 0
alpha bool values: true false

一旦向cout“写入”了boolalpha,我们就改变了cout打印bool值的方式。后续打印bool值的操作都会打印true或false而非1或0。

为了取消cout格式状态的改变,我们使用noboolalpha:

cout << boolalpha //设置cout的内部状态
	<< true 
	<< endl
	<< noboolalpha//将内部状态恢复为默认格式
	<< true << endl;



指定整型值的进制

默认情况下,整型值的输入输出使用十进制。

我们可以使用操纵符hex、oct和dec将其改为十六进制、八进制或是改回十进制:

cout << "default: " << 20 << " " << 1024 << endl;
cout << "octal: " << oct << 20 << " " << 1024 << endl;
cout << "hex: " << hex << 20 << " " << 1024 << endl;
cout << "decimal: " << dec << 20 << " " << 1024 << endl;

当编译并执行这段程序时,会得到如下输出:

注意,类似boolalpha,这些操纵符也会改变格式状态。它们会影响下一个和随后所有的整型输出,直至另一个操纵符又改变了格式为止。

操纵符hex、oct和dec只影响整型运算对象,浮点值的表示形式不受影响

在输出中指出进制

默认情况下,当我们打印出数值时,没有可见的线索指出使用的是几进制。

例如,20是十进制的20还是16的八进制表示?

当我们按十进制打印数值时,打印结果会符合我们的期望。

如果需要打印八进制值或十六进制值,应该使用showbase 操纵符。

当对流应用showbase 操纵符时,会在输出结果中显示进制,它遵循与整型常量中指定进制相同的规范:

  1. 前导0x表示十六进制。
  2. 前导0表示八进制。
  3. 无前导字符串表示十进制。

我们可以使用showbase修改前一个程序:

cout << showbase;// 当打印整型值时显示进制
	cout << "default: " << 20 << "    " << 1024 << endl;
cout << "in octal: " << oct << 20 << "   " << 1024 << endl;
cout << "in hex: " << hex << 20 << "   " << 1024 << endl;
cout << "indecimal: " << dec << 20 << "   " << 1024 << endl;

cout << noshowbase; //恢复流状态


修改后的程序的输出会更清楚地表明底层值到底是什么:

操纵符noshowbase恢复cout的状态,从而不再显示整型值的进制。

默认情况下,十六进制值会以小写打印,前导字符也是小写的x。我们可以通过使用uppercase操纵符来输出大写的X并将十六进制数字a-f以大写输出:

cout << uppercase << showbase << hex
<< "printed in hexadecimal: " << 20 << " " << 1024
<<nouppercase << noshowbase << dec << endl;


这条语句生成如下输出:

printed in hexadecimal; 0X14 0X400


我们使用了操纵符nouppercase、noshowbase和dec来重置流的状态。

控制浮点数格式

我们可以控制浮点数输出三个种格式:

  1. 以多高精度(多少个数字)打印浮点值
  2. 数值是打印为十六进制,定点十进制还是科学记数法形式
  3. 对于没有小数部分的浮点值是否打印小数点

默认情况下,浮点值按六位数字精度打印;

cout << 3.1111111111 << endl;

 

如果浮点值没有小数部分,则不打印小数点。

cout << 3.0000000000 << endl;

根据浮点数的值选择打印成定点十进制或科学记数法形式。

标准库会选择一种可读性更好的格式:非常大和非常小的值打印为科学记数法形式,其他值打印为定点十进制形式。

指定打印精度

默认情况下,精度会控制打印的数字的总数。

当打印时,浮点值按当前精度舍入而非截断。

因此,如果当前精度为四位数字,则3.14159将打印为3.142,如果精度为三位数字,则打印为3,14。
 

我们可以通过调用IO对象的precision成员或使用setprecision操纵符来改变精度。

precision成员是重载的。

  1. 一个版本接受一个int值,将精度设置为此值,并返回旧精度值。
  2. 另一个版本不接受参数,返回当前精度值。

setprecision操纵符接受一个参数,用来设置精度。

操纵符 setprecision和其他接受参数的操纵符都定义在头文件 iomanip中。

下面的程序展示了控制浮点值打印精度的不同方法:

// cout.precision返回当前精度值
	cout << "Precision: " << cout.precision()
		<< ", Value:" << sqrt(2.0) << endl;
	
	// cout.precision(12)将打印精度设置为12住数字
	cout.precision(12);
	
	cout << "Precision:" << cout.precision()
		<< ", Value:" << sqrt (2.0) << endl;
	
	// 另一种设置精度的方法是使用setprecision操纵符
	cout << setprecision(3);
	
	cout << "Precision:" << cout.precision()
		<< ", Value:" << sqrt(2.0) << endl;


编译并执行这段程序,会得到如下输出:

此程序调用标准库sqrt函数,它定义在头文件cmath中。

sqrt函数是重载的,不同版本分别接受一个float、double或long double参数,返回实参的平方根。

定义在iostream的操纵符
注意:*表示默认流状态
boolalpha将true和false输出为字符串
* noboolalpha将true和false输出为1,0
showbase对整型值输出表示进制的前缀
* noshowbase不生成表示进制的前缀
showpoint对浮点值总是显示小数点
*noshowpoint只有当浮点值包含小数部分时才显示小数点
showpos对非负数显示+
*noshowpos对非负数不显示+
uppercase在十六进制值中打印0X,在科学记数法中打印E
*nouppercase在十六进制值中打印0x, 在科学记数法中打印e
*dec整型值显示为十进制
hex整型值显示为十六进制
oct整型值显示为八进制
left在值的右侧添加填充字符
right在值的左侧添加填充字符
lnternal在符号和值之间添加填充字符
fixed浮点值显示为定点十进制
scientific浮点值显示为科学记数法
hexfloat浮点值显示为十六进制(C++11新特性)
defaultfloat重置浮点数格式为十进制(C++11新特性)
unitbuf每次输出操作后都刷新缓冲区
*nounitbuf恢复正常的缓冲区刷新方式
*skipws输入运算符跳过空白符
noskipws输入运算符不跳过空白符
flush刷新ostream缓冲区
ends插入空字符,然后刷新ostream缓冲区
endl插入换行,然后刷新ostream缓冲区

指定浮点数记数法

除非你需要控制浮点数的表示形式(如,按列打印数据或打印表示金额或百分比的数据),否则由标准库选择记数法是最好的方式。

通过使用恰当的操纵符,我们可以强制一个流使用科学记数法、定点十进制或是十六进制记数法。

  • 操纵符scientific改变流的状态来使用科学记数法。
  • 操纵符fixed改变流的状态来使用定点十进制。
  • 在新标准库中,通过使用hexfloat 也可以强制浮点数使用十六进制格式。
  • 新标准库还提供另一个名为defaultfloat的操纵符,它将流恢复到默认状态——根据要打印的值选择记数法。

这些操纵符也会改变流的精度的默认含义。

在执行 scientific、fixed或hexfloat后,精度值控制的是小数点后面的数字位数,而默认情况下精度值指定的是数字的总位数——既包括小数点之后的数字也包括小数点之前的数字。

使用fixed或scientific令我们可以按列打印数值,因为小数点距小数部分的距离是固定的:

cout << "default format: " << 100 * sqrt(2.0) << '\n'
	<< "scientific: " << scientific << 100 * sqrt(2.0) << '\n'
	<< "fixed decimal: " << fixed << 100 * sqrt(2.0) << '\n'
	<< "hexadecimal: " << hexfloat << 100 * sqrt(2.0) << '\n'
	<< "use defaults: " << defaultfloat << 100 * sqrt(2.0);


此程序会生成下面的输出:

默认情况下,十六进制数字和科学记数法中的e都打印成小写形式,我们可以用uppercase操纵符打印这些字母的大写形式。

打印小数点

强制打印小数点:
默认情况下,当一个浮点值的小数部分为0时,不显示小数点。showpoint 操纵符

cout << 10.0 << endl;// 打印10
cout << showpoint << 10.0 //打印10.0000
<< noshowpoint << endl; //恢复小数点的默认格式

操纵符noshowpoint恢复默认行为。下一个输出表达式将有默认行为,即,当浮点值的小数部分为0时不输出小数点。

输出补白

当按列打印数据时,我们常常需要非常精细地控制数据格式。

标准库提供了一些操纵符帮助我们完成所需的控制:

  1. setw指定下一个数字或字符串值的最小空间。
  2. left表示左对齐输出。
  3. right表示右对齐输出,右对齐是默认格式。
  4. internal控制负数的符号的位置,它左对齐符号,右对齐值,用空格填满所有中间空间。
  5. setfill允许指定一个字符代替默认的空格来补白输出。

setw类似endl,不改变输出流的内部状态。它只决定下一个输出的大小。
下面程序展示了如何使用这些操纵符:

	int i = -16;
	double d = 3.14159;
	//补白第一列,使用输出中最小12个位置
		cout << "i:" << setw(12) << i << "next col" << '\n'
		<< "d: " << setw(12) << d << "next col" << '\n';
	
		//补白第一列,左对齐所有列
		cout << left
			<< "i: " << setw(12) << i << "next col" << '\n'
			<< "d: " << setw(12) << d << "next col" << '\n'
			<< right; //恢复正常对齐
		
		//补白第一列,右对齐所有列
		cout << right
		<< "i: " << setw(12) << i << "next col" << '\n'
        << "d: " << setw(12) << d << "next col" << '\n';
		
		//补白第一列,但补在域的内部
	   cout << internal
		<< "i:" << setw(12)<< i << "next col" << '\n'
		   << "d: " << setw(12)<< d << "next col" << '\n';
	
	   //补白第一列,用#作为补白字符 符。
	   cout << setfill('#')
		   << "i: " << setw(12) << 1 << "next col" << '\n'
		   << "d: " << setw(12) << d << "next col" << '\n'
		   << setfill(' ');//恢复正常的补白字符

执行这段程序,会得到下面的输出:

定义在iomanip的操作符
setfill(ch)用ch填充空白
setprecision(n)将浮点精度设置为n
setw(w)读或写值的宽度为w个字符
setbase(b)将整数输出为b进制


控制输入格式

默认情况下,输入运算符会忽略空白符(空格符、制表符、换行符、换纸符和回车符)。

下面的循环

char ch;
while (cin >> ch)
cout << ch;


当给定下面输入序列时

a b         c
d

循环会执行4次,读取字符a到d,跳过中间的空格以及可能的制表符和换行符。

此程序的输出是

abcd

操纵符 noskipws会令输入运算符读取空白符,而不是跳过它们。为了恢复默认行为,我们可以使用skipws操纵符:

cin >> noskipws;// 设置cin 读取空白符
while (cin >> ch)
cout << ch;
cin >> skipws; //将cin恢复到默认状态,从而丢弃空白符


给定与前一个程序相同的输入,此循环会执行7次,从输入中既读取普通字符又读取空白符。此循环的输出为

a b        c
d


 

标签:输出,格式化,cout,打印,C++,操纵,默认,格式,输入
From: https://blog.csdn.net/2301_80224556/article/details/137197791

相关文章

  • C++类基础8——嵌套类
    嵌套类一个类可以定义在另一个类的内部,前者称为嵌套类或嵌套类型。下面是一个使用C++嵌套类的示例:#include<iostream>classOuterClass{public:classInnerClass{public:voidprintMessage(){std::cout<<"HellofromInnerClass!......
  • 【华为OD机试C++】提取不重复的整数
    《最新华为OD机试题目带答案解析》:最新华为OD机试题目带答案解析,语言包括C、C++、Python、Java、JavaScript等。订阅专栏,获取专栏内所有文章阅读权限,持续同步更新!文章目录描述输入描述输出描述示例代码描述输入一个int型整数,按照从右向左的阅读顺序,返回......
  • 模拟比赛-14届研究生组C++省赛
    A工作时长题意:若干条打卡记录字符串(年月日时分秒格式),保证打卡记录相邻。求该年工作时长。思路:对字符串处理,转换格式为秒数,排序后相邻相减求和。总结:2月有29天的情况要被4整除,如果能被100整除的话,一定要被400整除。structData{ intmonth;//5 intday;//8 inthour;//......
  • 选择题部分的读取写入,以及重复进入的保证列表内数据不丢失的方法以及判断重复试题输
    1.思路讲解1.1首先读取部分,我们事先准备好一个文件夹,在内部创建一个文件,注意文件名不可重复,我这边使用了datetime.date.today()来达到文件名始终为当前日期的方式,再利用os.path.exists(path)来判断文件路径是否存在,如若不存在就新建,存在就追加1.2进行读取时,我们找到......
  • Qt/C++入门基础学习001-绘图基础
    这一节介绍Qt的绘图基础知识,我们都知道,Qt里绘图使用的是QPainter,但是首先需要弄明白:在什么上绘图和在哪里绘图,然后才是怎么绘图,我们就围绕这几个问题来展开。在什么上绘图TheQPaintDeviceclassisthebaseclassofobjectsthatcanbepaintedonwithQPainter.Apa......
  • 【前端面试3+1】06继承方式及优缺点、缓存策略、url输入到渲染全过程、【二叉树中序遍
    一、继承有哪些方式?以及优缺点        继承的方式包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承和组合式继承。1.原型链继承:实现方式:将子类的原型指向父类的实例来实现继承。优点:简单易懂,代码量少。缺点:存在引用类型共享的问题。functionPare......
  • 突破编程_C++_C++14新特性(变量模板)
    1变量模板在C++14中的引入与扩展在C++14中,变量模板的引入与扩展为编程带来了许多便利,特别是在泛型编程方面。这一特性允许我们直接定义模板变量,而不需要将其包装在模板类或模板函数中,从而使得代码更加直观和简洁。首先,我们来详细了解一下C++14之前模板的使用限制。......
  • 突破编程_C++_网络编程(OSI 七层模型(传输层))
    1传输层的功能与特点1.1传输层的功能传输层是OSI七层模型中的第四层,它位于网络层和应用层之间,起着承上启下的关键作用。以下是关于OSI传输层功能的详细讲解:一、提供可靠的数据传输服务传输层的主要任务是确保数据在源主机和目标主机之间可靠地传输。它通过一系列......
  • 【C++实验1】学生成绩信息管理系统题解
    【问题描述】编写一个基于结构体得学生成绩信息管理系统。主要功能如下:1.用结构体存放所有数据。2.每个功能都用函数实现。3.输入10个学生的学号和三门课程的成绩。4.计算每个学生的总分。5.按总分从高到低排序。6.加上名次一列。7.输出最后的二维表格样式的成......
  • C++--STL函数模板
    一.函数模板我们可以定义一个函数模板(functiontemplate),而不是为每个类型都定义一个函数。一个函数模板就是一个蓝图,可用来生成针对特定类型的函数。例如用于比较两个数字的大小compare()函数的模板如下:template<typenameT>intcompare(constT&v1,constT&v2){......