C++STL开发温习与总结(六): 6.C++语言输入/输出流定义之输入/输出格式控制

简介: C++STL开发温习与总结(六): 6.C++语言输入/输出流定义之输入/输出格式控制

原博主博客地址:http://blog.csdn.net/qq21497936

本文章博客地址:http://mp.blog.csdn.net/postedit/79177645


C++STL开发温习与总结(六):

6.C++语言输入 /输出流定义之输入 /输出格式控制


       本章开始正式进入标准库的温习。


1.C++语言输入/输出流概述


       在C++语言系统中所有的输入/输出流操作都是借助ios类及其派生类对象实现的。ios派生类ostream和istream。cout是ostream的一个对象,cin是istream的一个对象。此两对象的特殊之处在于它们是编译器直接认识的少数几个系统级的对象,其包含于头文件<iosteam>。

        符号“<<”和“>>”是在类(派生类)中定义的重载运算符。


2.输入/输出格式控制


       输出输出格式控制决定了输入或输出的格式,对于实际系统非常重要,下面列举了输入输出格式控制的几种方式:


2-1枚举常量(ios类中的)


       在根基类ios中定义有3个用户需要使用的枚举类型,由于它们是在公用成员部分定义的,所以其中的每个枚举型常量在加上ios::前缀后都可以为本类成员函数和所有外部函数访问。在3个枚举类型中有一个无名枚举类型。

       第一个定义为无名枚举类型,每个枚举常量都是用于设置控制输入输出格式的标志使用的:

enum {
  skipws,
  left,
  right,
  internal,
  dec,
  oct,
  hex
  showbase,
  showpoint,
  uppercase,
  showpos,
  scientific,
  fixed,
  unitbuf,
  stdio
};
  • skipws:设置标志后,从流中输入数据时跳过当前位置及后面的所有连续的空白字符,从第一个非空白字符起读数,否则不跳过空白字符。(空白字符:空格、\t、\r、\n)。
  • left、right、internal:在指定的域宽内分别对齐左、右、中输出,注意internal使数值的符号按左对齐,数值本身按右对齐。域宽内剩余的字符位置用填充符填充。
  • dec、oct、hex:设置标志后,使以后的数值按照十进制、八进制、十六禁止输出。
  • showbase:设置标志后,使数值输出的前面加上“基指示符”。十进制无,八进制为0,十六禁止为0x。
  • showpoint:强制输出的浮点数中带有小数点和小数尾部的无效数字0.
  • uppercase:使输出的十六进制数和浮点数中使用的字母为大写,缺省为不设置(即小写)。
  • showpos:使输出的整数前带有正好“+”,缺省为不设置,即输出的正数前不带任何符号。
  • scientific、fixed:设置scientific后,浮点数按科学表示法输出;fix设置后,使浮点数按定点表示法输出,只能任设其一。缺省由系统适配自动选择合适的输出表示。
  • unitbuf、stdio:这两个很少使用,未介绍。

       第二个枚举类型open_mode,每个常量规定一种文件打开的方式,在定义文件流和打开文件时使用:

enum open_mode {
  in,
  out,
  ate,
  app,
  trunc,
  nocreate,
  noreplace,
  binary
};

      第三个枚举类型,每个枚举常量用于对文件指针的定位操作上:

enum seek_dir{
  beg,
  cur,
  end
}


2-2成员函数(ios类中的)


       ios类提供成员函数对流的状态进行检测和进行输入输出格式控制等操作,所有成员函数如下:

  • int bad():操作出错时返回非0值。
  • int eof():读取到流中最后的文件结束符时返回非0值。
  • int fail():操作失败返回非0值。
  • void clear():清除bad、eof和fail所对应的标志状态,使之恢复为正常状态值0,使good标志状态恢复为1。
  • char fill():返回当前使用的填充字符。
  • char fill(char c):重新设置流中用于输出数据的填充字符为c的值,返回此前的填充字符。系统预设置填充字符为空格
  • long flags():返回当前用于I/O控制的格式状态字。
  • long flags(long f):重新设置格式状态字为f的值,返回此前的格式状态字。
  • int good():操作正常时返回非0值,当操作出错、失败或者读到文件结束符时均为不正常,则返回0。
  • int precision():返回浮点数输出精度,即输出的有效数字的位数。
  • int precision(int n):设置浮点数的输出精度为n,返回此前的输出精度。系统预设置的输出精度为6,即输出的浮点数最多具有6位有效数字。
  • int rdstate():操作正常是返回0,否则返回非0值,它与good正好相反。
  • long setf(long f):根据参数f设置相应的格式化标志,返回此前的设置。该参数f所对应的实参为无名枚举类型中枚举常量(又称格式化常量),可以同时使用一个或多个常量,每两个常量之间要用按位或操作符连接。如当需要左对齐输出,并使数值中的字母大写时,则调用改函数的实参为ios::left | ios::uppercase。
  • long unsetf(long f):根据参数f清除相应的格式化标志,返回此前的设置。如要清除此前的左对齐输出设置,恢复缺省的右对齐输出设置,则调用该函数的实参为ios::left。
  • int width():返回当前的输出域宽。若返回数值0则表明没有为刚才输出的数值设置输出域宽,输出域宽是指输出的值再流中所占有的字节数。
  • int width(int w):设置下一个数据值的输出域宽为w,返回为输出上一个数据值所规定的域宽,若无规定则返回0。注意:此设置不是一直有效,而是只对下一个输出数据有效。

   下面的demo我们姑且认为是方式一

#include <iostream>
using namespace std;
int main()
{
    int x = 30, y = 300, z = 1024;
    cout << x << ' ' << y << ' ' << z << endl;
    cout.setf(ios::oct); // 设置位8进制输出
    cout << x << ' ' << y << ' ' << z << endl;
    cout.unsetf(ios::oct);
    cout.setf(ios::hex);
    cout << x << ' ' << y << ' ' << z << endl;
cout.setf(ios::showbase | ios::uppercase);   
cout << x << ' ' << y << ' ' << z << endl;
    cout.unsetf(ios::showbase | ios::uppercase);
    cout << x << ' ' << y << ' ' << z << endl;
    cout.unsetf(ios::hex);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

       以上代码可能会运行错误,存在调不出库的情况,本人使用的mingw32编译器,具体细节请查看:

     《关于 QtCreartor编写纯C++程序调用不到C++某些标准库和枚举以及运行错误的解决方法》:

       http://blog.csdn.net/qq21497936/article/details/78983051

现在已改为msvc2015,调用没有问题,运行时,输出结果如下图,与预期不同。

图片.png

原因:

       除非知道当前没有设置基标志,否则 ios::setf(_IFlags) 不应和 ios::dec、ios::oct 或 ios::hex 的标志值一起使用。格式化的输入/输出函数和运算符假定只设置了一个基。改用 ios_base。例如,setf( ios_base::oct, ios_base::basefield ) 清除所有基信息并将基设置成八进制。

程序改为方式二:

#include <iostream>
using namespace std;
int main()
{
    int x = 30, y = 300, z = 1024;
    cout << x << ' ' << y << ' ' << z << endl;
#if 0
    cout.setf(ios::oct); // 设置位8进制输出
#else
    cout.setf(ios::showbase); // 显示进制前缀 八进制36显示为036
    // 清除所有基信息并将基设置成八进制,必须最开始先调用一次ios_base::basefield,
    // 后续单独设置ios_base::oct等才会生效
    cout.setf(ios_base::oct, ios_base::basefield);
#endif
    cout << x << ' ' << y << ' ' << z << endl;
#if 0
    cout.unsetf(ios::oct);
    cout.setf(ios::hex);
#else
//    cout.setf(ios_base::hex, ios_base::basefield);
    cout.unsetf(ios_base::oct);
    cout.setf(ios_base::hex);
#endif
    cout << x << ' ' << y << ' ' << z << endl;
#if 0
    cout.setf(ios::showbase | ios::uppercase); // 设置基指示符输出和数值中的字母大写输出
#else
    cout.setf(ios_base::uppercase);
#endif
    cout << x << ' ' << y << ' ' << z << endl;
    cout.setf(ios_base::dec, ios_base::basefield);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

运行结果:

图片.png

以下是第三种风格(建议使用方式三替代方式一,不建议使用方式二):

#include <iostream>
using namespace std;
int main()
{
    int x = 30, y = 300, z = 1024;
    cout << x << ' ' << y << ' ' << z << endl;
    cout << oct << x << ' ' << y << ' ' << z << endl;
    cout << hex << x << ' ' << y << ' ' << z << endl;
    cout << showbase << uppercase << x << ' ' << y << ' ' << z << endl;
    cout << dec << x << ' ' << y << ' ' << z << endl;
    return 0;
}

图片.png

2-3格式控制操作符


       数据输入输出的格式更便捷的形式是使用系统头文件<iomanip.h>中提供的操作符,使用这些不需要调用成员函数,只要把他们作为插入操作符<<(个别作为提取操作符>>)的输出对象即可。再成员函数章节中的方式三则是使用该方法。

  • dec,转换为十进制输出整数,系统预制的进制。
  • oct,转换为按八进制输出整数。
  • hex,转换为按十六进制输出整数。
  • ws,从输入流中读取空白字符。
  • endl,输出换行符’\n’并刷新流。(刷新流是指把缓冲区的内容立即写入到对应的物理设备上)。
  • ends,输出一个空字符’\0’。
  • flush,至刷新一个输出流。
  • setiosflags(long f),设置f所对应的格式化标准,功能与setf(longf)成员函数相同。
  • resetiosflags(long f),清楚F所对应的格式化标志,功能与unsetf(longf)成员函数相同。输出后返回流。
  • setfill(int c),设置填充字符位ASCII码为c的字符。
  • setprecision(int n),预置浮点数的输出精度为n。
  • setw(int w),设置下一个数据的输出域宽度位w。

       在上面的操纵符中,dec、oct、hex、endl、ends、flush和ws除了在iomanip.h中有定义外,再iosream.h中也又定义。所以程序中使用这些不带标参数的标记符时,可只包含iostream.h而不需要包含iomanip.h。

       dec、hex和oct这三个函数的作用和c语言的printf中的%d、%x和%o相同,用于输入/输出整数数制的设定。当用户输入时,若输进违例数值,则强制一个零给目标。一旦用上述某个函数设置书之后,在本程序执行中直至下一个设置前,该设置一直有效(已代码验证),且cin与cout不互相影响。

       回车换行函数endl用户产生一个”\n”码,即在输出流中插入0x0d0a内码。所以cout<<endl等效于cout<<’\n’。流操作符ends等于’\0’,该字符主要用于在一组字符后充当字符串结束的标志。

       强制flush主要是为了提高输出效率,在输出时,系统并不会把每个输出项都立即送外外设,而是等待积满某一个缓冲区(如果集装箱)后才一起送出。但用本函数flush即可时正在缓冲区中待输出的内容都被立即输出,同时输出缓存也被清除,此函数多用于流式文件输出当中。

       用取消输入结束符函数ws表示可以省去输入时用作代表一个输入项结束的空格或(Tab)键。这时的输入结束判决完全由对应的变量类型来决定。例如如下代码所示:

char c,d;
cin >> c >> d;

此时的输入:x y<CR>与xy<CR>等效,如下图

图片.png

       如果使用ws函数后,这个效果始终存在,但对数值变量无效。

       输入/输出域宽度设置函数setw(int)用整数参数来指定输入/输出域的宽度。相当于c语言库函数scanf、prinf中的”%”格和格式符的作用。该函数的设置仅其后的一个数据项有效。当用于输出时,若所输出的实际宽度小于设定的数据域宽度,则数据缺省一律向右对齐,反之则按数据的实际宽度输出。当用户输入时,若输入数据的实际宽度超过设定的数据宽度时,超出的数据部分被阶段且被作为下一项输入数据内容。利用此特性可以防止在变量输入时出现的越界情况,但不好用也容易出错。

图片.png

图片.png

图片.png

       向输出域中填充字符的函数setfill(int)常与setw(int)函数联合使用,如下图:

图片.png

       setprecision(int)设置浮点数输出显示精度。

图片.png

       读取/设置域宽的函数int width() constint width(int)

       读取/设置填充字符的函数char fill() constchar fill(char)

       读取/设置浮点数有效位长的函数int precision() constint precision(int)

       以上三组函数 ,必须用发送消息的格式来引用(即以cout.或cin.的形式)。

图片.png

原博主博客地址:http://blog.csdn.net/qq21497936

本文章博客地址:http://mp.blog.csdn.net/postedit/79177645



相关文章
|
8天前
|
算法 C语言 C++
【c++丨STL】list的使用
本文介绍了STL容器`list`的使用方法及其主要功能。`list`是一种双向链表结构,适用于频繁的插入和删除操作。文章详细讲解了`list`的构造函数、析构函数、赋值重载、迭代器、容量接口、元素访问接口、增删查改操作以及一些特有的操作接口如`splice`、`remove_if`、`unique`、`merge`、`sort`和`reverse`。通过示例代码,读者可以更好地理解如何使用这些接口。最后,作者总结了`list`的特点和适用场景,并预告了后续关于`list`模拟实现的文章。
22 7
|
25天前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
51 4
|
27天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
62 5
|
27天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
48 2
|
1月前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
50 0
|
11天前
|
存储 编译器 C语言
【c++丨STL】vector模拟实现
本文深入探讨了 `vector` 的底层实现原理,并尝试模拟实现其结构及常用接口。首先介绍了 `vector` 的底层是动态顺序表,使用三个迭代器(指针)来维护数组,分别为 `start`、`finish` 和 `end_of_storage`。接着详细讲解了如何实现 `vector` 的各种构造函数、析构函数、容量接口、迭代器接口、插入和删除操作等。最后提供了完整的模拟实现代码,帮助读者更好地理解和掌握 `vector` 的实现细节。
22 0
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
96 4
|
2月前
|
算法 C++
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
51 5
|
2月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
82 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
94 5