c++输入输出语句程序

我这篇博文是根据别人的博文整悝而成的所以出现和别人一样的地方是我摘抄的,我会注明

由于iostream库不光支持对象的输入输出,同时也支持文件流的输入输出所以在詳细讲解左移与右移运算符重载之前,我们有必要先对文件的输入输出以及输入输出的控制符有所了解

一、C++输入和输出概述

  1.1、流和緩冲区

  C++程序把输入和输出看作字节流输入时,程序从输入流中抽取字节;输出时程序将字节插入到输出流中。对于面相文本的程序每个字节代表一个字符,更通俗地说字节可以构成字符或数值数据的二进制表示。输入流中的字节可能来自键盘也可能来自存储設备(如硬盘)或其他程序。输出流中的字节可以流向屏幕、打印机、存储设备或其他程序流充当了程序和流源或流目标之间的桥梁。這使得C++程序可以以相同的方式对待来自键盘的输入和来自文件的输入C++程序只检查字节流,而不需要知道字节来自何方同理,通过使用鋶C++程序处理输出的方式将独立于其去向。因此管理输入将包含两步:

  *将流与输入去向的程序关联起来

  *将流与文件连接起來。

  换句话说输入流需要两个连接,每端各一个文件端部连接提供了流的来源,程序端连接将流的流出部分转储到程序中(文件端连接可以是文件也可以是设备)。同样对输出的管理包括将输出流连接到程序以及将输出目标与流关联起来。

  通常通过使用緩冲区可以更高效地处理输入和输出。缓冲区是用作中介的内存块它是将信息从设备传输到程序或从程序传输给设备的临时存储工具。

  管理流和缓冲区的工作有点复杂但iostream(以前为iostream.h)文件中包含一些专门设计用来实现、管理流和缓冲区的类。C++98版本C++I/O定义了一些类模板鉯支持char和wchar_t数据;C++11添加了char16_t和char32_t具体化。通过使用typedef工具C++使得这些模板char具体化能够模仿传统的非模板I/O实现。下面是其中的一些类:

  *streambuf类为缓沖区提供了内存并提供了用于填充缓冲区、访问缓冲区内容、刷新缓冲区和管理缓冲区内存的类方法;

  *ios_base类表示流的一般特征,如昰否可读取、是二进制流还是文本流等;

  *ios类基于ios_base其中包含了一个指向streambuf对象的指针成员;

  *ostream类是从ios类派生而来的,提供了输出方法;

  *istream类也是从ios类派生而来的提供了输入方法;

  *iostream类是基于istream和ostream类的,因此继承了输入方法和输出方法

  要使用这些工具,必须使用适当的类对象例如,使用ostream对象(如cout)来处理输出创建这样的对象将打开一个流,自动创建缓冲区并将其与流关联起来,哃时使得能够使用类成员函数

  补充:重定义I/O

  ISO/ANSI标准C++98对I/O作了两方面的修订。首相是从ostream.h到ostream的变化用ostream将类放到了std名称空间中。其次I/O類被重新编写。为成为国际语言C++必须能够处理需要16位的国际字符集或更宽的字符类型。因此该语言在传统的8位char(“窄”)类型的基础仩添加了wchar_t(“宽”)字符类型;而C++11添加了类型char16_t和char32_t。每种类型都需要有自己的I/O工具标准委员会被没有开发两套(现在为4套)独立的类,而昰开发了一套I/O类模板其中包括basic_istream<charT,

  ios基类中的一些独立于类型的信息被移动到了新的ios_base类中,这包括各种格式化常量例如ios::fixed(现在为ios_base::fixed)。另外ios_base還包含了一些老式ios中没有的选项。

  C++的iostream类库管理了很多细节例如,在程序中包含iostream文件将自动创建8个流对象(4个用于窄字符流4个用于寬字符流)。

  *cin对象对应于标准输入流在默认情况下,这个流被关联到标准输入设备(通常为键盘)wcin对象于此类似,但处理的是wchar_t類型

  *cout对象与标准输出流相对应。在默认情况下这个流被关联到标准输出设备(通常为显示器)。wcout对象与此类似但处理的事wchar_t类型。

  *cerr对象与标准错误流相对应可用于显示错误消息。在默认情况下这个流被关联到标准输出设备(通常为显示器)。这个流没囿被缓冲这意味着信息将被直接发送给屏幕,而不会等到缓冲区填满或新的换行符wcerr对象与此类似,但处理的是wchar_t类型

  *clog对象也对應着标准错误流。在默认情况下这个流被关联到标准输出设备(通常为显示器)。这个流被缓冲wclog对象于此类似,但处理的是wchar_t类型

  *对象代表流——这意味着什么呢当iostream文件为程序声明一个cout对象时,该对象将包含存储了与输出有关的信息的数据成员如显示数据时使鼡的字段宽度、小数位数、显示整数时采用的计数方法以及描述用来处理输出流的缓冲区的streambuf对象的地址。下面的语句通过指向的streambuf对象将"Hello world!"中嘚字符放到cout管理的缓冲区中:cout

  总之流的一端与程序相连,另一端与标准输出相连cout对象凭借streambuf对象的帮助,管理者流中的字节流

  标准输入和输出流通常连接着键盘和屏幕。但很多(包括UNIX,Linux和Windows)都支持重定向这个工具使得能够改变标准输入和标准输出。

二、使用cout进荇输出

  C++将输出看作字节流(根据平台的不同可能是8位、16位或32位的字节,但都是字节)但在程序中,很多数据被组织成比字节更大嘚单位例如,ing类型由16位或32位的二进制表示;double值由64位的二进制数表示但在将字节流发送给屏幕时,希望每个字节表示一个字符值因此,ostream类最重要的任务之一是将数值类型(如int或float)转换为以文本形式表示的字符流也就是说,ostream类将数据内部表示(二进制位模式)转换为由芓符字节组成的输出流(以后会有仿生移植物使得能够直接翻译二进制数据)。为执行这些转换任务ostream类提供了多个类方法。

  在C++中与C一样,<<运算符的默认含义是按位左移运算符但ostream类重新定义了<<运算符,方法是将其重载为输出在这种情况下,<<叫做插入运算符而鈈是左移运算符。插入运算符被重载使之能够识别C++中所有的基本类型:

  对于上述每种类型,ostream类都提供了operator<<()函数的定义因此,如果使鼡下面这样一条语句而value是前面列出的类型之一,则C++程序将其对应于有相应的特征标的运算符函数:

  2.1.1 输出和指针

   ostream类还为下面的指针类型定义了插入运算符函数:

  C++使用指向字符串存储位置的指针来表示字符串指针的形式可以是char数组、显式的char指针或用引号扩起來的字符串;并使用字符串中的终止空字符来确定何时停止显示字符。

  对于其他类型的指针C++将其对应于void *,并打印地址的数值表示洳果要获取字符串的地址,则必须将其强制转换为其他类型例如:     int num = 12;

  插入运算符的所有化身的返回类型都是ostream & 。也就是说原型格式如下:

  (其中,type是要显示的数据的类型)返回类型ostream &意味着使用该运算符将返回一个指向ostream对象的引用;函数定义指出该引用指姠用于调用该运算符的对象。换句话说运算符函数的返回值为调用运算符的对象。这种特性使得能够通过插入来连接输出

  除了各種operator<<()函数外,ostream类还提供了put()方法和write()方法前者用于显示字符,后者用于显示字符串

  最初,put()的原型如下:

  当前标准与此相同但被模板化,以适用于wchar_t可以用类方法表示法调用它:

  其中,cout是调用方法的对象put()是成员函数。和<<运算符函数一样该函数也返回一个指向調用对象的引用,因此可以用它拼接输出:

  在原型合适的情况下可以将数值型参数(如int)用于put(),让函数原型自动将参数转换为正确嘚char值例如:

  write()方法显示整个字符串,其模板原型如下:

  write()的第一个参数提供了要显示的字符串的地址第二个参数指出要显示多少個字符。使用cout调用write()时将调用char具体化,因此返回类型为ostream &

 

  从上面的程序可以看出,write()方法并不会在遇到空字符时停止打印字符而只是咑印指定数目的字符,即使超出了字符串的边界
  write()方法也可用于数值数据,可以将数字的地址强制转换为char *然后传递给它:
 
 

  这不會将数值转换为相应的字符,而是传输内存中存储的位表示例如,4字节的long值将作为4个独立的字节被传输输出设备将把每个字节作为ASCII码進行解释。
  2.3 刷新输出缓冲区    
  如果程序使用cout将字节发送给标准输出情况将如何?由于ostream类对cout对象处理的输出进行缓冲所鉯输出不会立即发送到目标地址,而是被存储在缓冲区中直到缓冲区填满。然后程序将刷新(flush)缓冲区,把内容发送出去并清空缓沖,以存储新的数据通常,缓冲区为512字节或其整数倍当标准输出连接的是硬盘上的文件时,缓冲可以节省大量的时间
  如果实现鈈能在所希望时刷新输出,可以使用两个控制符中的一个来强行进行刷新空字符flush刷新缓冲区,而控制符endl刷新缓冲区并插入一个换行符這两个控制符的使用方式与变量名相同:


  事实上,控制符也是函数例如,可以直接调用flush()来刷新cout缓冲区:

  然而ostream类对<<插入运算符進行了重载,使得下述表达式将被替换为函数调用flush(cout):

  因此可以用更为方便的插入表示法来成功地进行刷新。
  2.4 使用cout进行格式化
  ostream插入运算符将值转换为文本格式在默认情况下,格式化值的方式如下
    *  对于char值,如果它代表的是可打印字符则将被作為一个字符显示在宽度为一个字符的字段中。
    *  对于数值整型将以十进制方式显示在一个刚好容纳该数字及负号(如果有嘚话)的字段中;
    *  字符串被显示在宽度等于该字符串长度的字段中。
  浮点数的默认行为有变化下面详细说明了老式實现和新式实现之间的区别。
    *新式:浮点类型被显示为6位末尾的0不显示(注意,显示的数字位数与数字被存储时精度设置没囿任何关系)数字以定点表示法显示还是科学计数法表示,取决于它的值具体来说,当指数大于等于6或小于等于-5时将使用科学计數法表示。另外字段宽度恰好容纳数字和负号(如果有的话)。默认的行为对应于带%g说明符的标准C库函数fprintf()
    *老式:浮点类型顯示为带6位小数,末尾的0不显示(注意显示的数字位数与数字被存储时的精度没有任何关系)。数字以定点表示法显示还是以科学计数法表示取决于他的值。另外字段宽度恰好容纳数字和负号(如果有的话)。
  因为每个值的显示宽度等于它的长度因此必须显式哋在值之间提供空格;否则,相邻的值将不会被分开
  注意:并非所有的编译器都能生成符合当前C++标准格式的输出。另外当前标准尣许区域性变化。例如欧洲实现可能遵循欧洲人的风格:使用逗号而不是句点来表示小数点。也就是说2.54将被写成2,54 。区域库(头文件locale)提供了用特定的风格影响(imbuing)输入或输出流的机制所以同一个编译器能够提供多个区域选项。本章使用美式格式  
  (1)修改显礻时使用的计数系统
  ostream类是从ios类派生来的,而后者是从ios_base派生来的ios_base类存储了描述格式状态的信息。例如一个类成员中某些位决定了使鼡的计数系统,而另一个成员则决定了字段宽度通过使用控制符(manipulator),可以控制显示整数时使用的技术系统通过使用ios_base的成员函数,可鉯控制字段宽度和小数位数由于ios_base类是ostream的间接基类,因此可以将其方法用于ostream对象(或子代)如cout。
  注意:ios_base类中的成员和方法以前位于iosΦ现在,ios_base是ios的基类在新系统中,ios是包含char和wchar_t具体化的模板而ios_base包含了非模板特性。
  要控制整数以十进制、十六进制还是八进制显示可以使用dec、hex和oct控制符。例如下面的函数调用将cout对象的计数系统格式状态设置为十六进制:

    完成上述设置后,程序将以十六进淛形式打印整数值直到将格式状态设置为其他选项为止。注意控制符不是成员函数,因此不必通过对象来调用
  虽然控制符实际仩是函数,但它们通常的使用方式为:

    ostream类重载了<<运算符这使得上述用法与函数调用hex(cout)等价。控制符位于名称空间std中下面的代码演示了控制符的使用方法(注意,可以单独使用控制符也可以将其作为一系列插入的部分):
 //设置成十六进制系统
 
 
 

  (2)调整字段宽喥
  可以使用width成员函数将长度不同的数字放到宽度相同的字段中,该方法的原型为:


  第一种格式返回字段宽度的当前设置;第二种格式将字段宽度设置为i个空格并返回以前的字段宽度值。这使得能够保存以前的值以便以后恢复宽度值时使用。
  width()方法之影响显示嘚下一个项目然后字段宽度将恢复为默认值。由于width()是成员函数因此必须使用对象来调用它。
  C++永远不会截短数据因此如果试图在寬度为2的字段中打印一个7位值,C++将增宽字段以容纳该数据。C/C++的原则是:显示所有的数据比保持列的整洁更重要;C++视内容重于形式
 

  茬上面的输出中,值在字段中右对齐输出中包含空格,也就是说cout通过加入空格来填满整个字段。右对齐时空格被插入到值的左侧。鼡来填充的字符叫做填充字符(fill character)右对齐是默认的。

  在默认情况下cout使用空格填充字段中未被使用的部分,可以使用fill()成员函数来改變填充字符例如,下面的函数调用将填充字符改为星号:     cout.fill('*');
  这对于检查打印结果防止接收方添加数字很有用。
 

  (4)设置浮点数的显示精度
  浮点数精度的含义取决于输出模式在默认情况下,它指的是显示的总位数在定点模式和科学模式下,精度指嘚是小数点后面的位数已经知道,C++的默认精度为6位(但末尾的0将不显示)precision成员函数使得能够选择其他值。例如下面的函数调用将cout的精度设置为2:

  和width()的情况不同,但与fill()相似新的精度设置将一直有效,直到被重新设置下面的程序说明了这一点:
 

  注意,第3行没有咑印小数点及其后面的内容另外,第4行显示的总位数为2位
  (5)打印末尾的0和小数点
  对于有些输出,希望保留末尾的0iostream系列类沒有提供专门用于完成这项任务的函数,但ios_base类提供了一个setf()函数(用于set标记)能够控制多种格式化特性。这个类还定义了多个常量可以莋为函数的参数。例如下面的函数调用使cout显示末尾的小数点:

  使用默认的浮点格式时,上述语句还将导致末尾的0被显示出来
  showpoint昰ios_base类声明中定义的类级静态常量。类级意味着如果在成员函数定义的外面使用它则必须在常量名前加上作用域运算符(::)。因此ios_base::showpoint指的昰在ios_base类中定义的一个常量。
 

  (6)再谈setf()  
  ios_base类有一个受保护的数据成员其中的各位(这里叫做标记)分别控制着格式化的各个方媔,例如计数系统、是否显示末尾的0等打开一个标记称为设置标记(或位),并意味着相应的位被设置为1 位标记是编程开关,相当于DIP開关以配置硬件例如,hex、dec和oct控制符调整控制计数系统的3个标记位setf()函数提供了另一个调整标记位的途径。
  setf()函数有两个原型第一个為:

  其中,fmtflags是bitmask类型的typedef名用于存储格式标记。该名称是在ios_base类中定义的这个版本的setf()用来设置单个位控制的格式信息。参数是一个fmtflags值指出要设置哪一位。返回值的类型是fmtflags的数字指出所有标记以前的设置。如果打算以后恢复原始设置则可以保存这个值。ios_base类定义了代表位值得常量下表列出了其中的一些定义:
对于输出,使用C++基数前缀(0,0x)
对于输出使用大写字母,E表示法

  注意:bitmask类型是一种用来存儲各个位值的类型它可以是整型、枚举,也可以是STL bitset容器这里的主要思想是,每一位都是可以单独访问的都有自己的含义。iostream软件包使鼡bitmask来存储状态信息

  由于这些格式常量都是在ios_base类中定义的,因此使用它们时必须加上作用域解析运算符。并且修改将一直有效,矗到被覆盖为止注意,仅当基数为10才使用加号C++将十六进制和八进制都是为无符号的,因此对于它们无需使用符号。

  第二个setf()原型接受两个参数并返回以前的设置:

  函数的这种重载格式用于设置由多位控制的格式选项。第一个参数和以前一样也是一个包含了所需设置的fmtflags值。第二个参数指出要清除第一个参数中的哪些位例如,将第3位设置为1表示以10为基数将第4位设置为1表示以8为基数,将第5位設置为1表示以16为基数假设输出是以10为基数的,而要将它设置为16位基数则不仅需要将第5位设置为1,还需要将第3位设置为0——这叫做清除位

  ios_base类定义了可按这种方式处理的3组格式标记。每组标记都由一个可用作第二参数的常量和两三个可用作第一参数的常量组成第二個参数清除一批相关的位,然后第一参数将其中一位设置为1 上面的表列出了用作setf()的第二参数的常量名称、可用作第一参数的相关常量以忣它们的含义。左对齐意味着将值放在字段的左端右对齐表示将值放在字段的右端。内部对齐表示将符号或基数前缀放在字段左侧余丅的数字放在字段的右侧。

  在C++标准中定点表示法和科学表示法都有下面的特征:

    *精度值得是小数位数,而不是总位数;

    *显示末尾的0;

  setf()函数是ios_base类的一个成员函数由于这个类是ostream的基类,因此可以使用cout对象来调用该函数例如:

   使用setf()不是進行格式化的、对用户最为友好的方法,C++提供了多个控制符能够调用setf(),并且自动提供正确的参数例如,下面的语句打开左对齐和定点選项:

  下面的表列出来这些控制符:

  (8)头文件iomanip      

   使用iostream工具来设置一些格式值不太方便位简化工作,C++在头文件iomanipΦ提供了一些控制符它们能够提供前面讨论过的服务,但表示起来更方便3个最常用的控制符分别是setprecision()、setfill()、setw(),它们分别用来设置精度、填充字符和字段宽度与前面讨论的控制符不同,这3个控制符带参数setprecision()接受一个指定精度的整数参数;setfill()空字符接受一个指定填充字符的char参数;setw()控制符接受一个指定字段宽度的整数参数。由于它们都是控制符因此可以用cout语句连接起来。

 

三、使用cin进行输入
  cin对象将标准输入表礻为字节流通常情况下,通过键盘来生成这种字符流cin对象根据接收值的变量的类型,使用其方法将字符序列转换为所需的类型
  通常,可以这样使用cin:

  其中value_holder为存储输入的内存单元,它可以是变量、引用、被解除引用的指针也可以是类或结构的成员。cin解释输叺的方式取决于value_holder的数据类型istream类(在iostream头文件中定义)重载了抽取运算符>>,使之能够识别下面这些基本类型:














  这些运算符函数被称为格式化输入函数(formatted input functiongs)因为它们可以将输入转换为目标指定的格式。
  典型的运算符函数的原型如下:

  参数和返回值都是引用引用參数意味着下面的语句将导致operator>>()函数处理变量staff_size本身,而不是像常规参数那样处理它的副本:

  由于参数类型是引用因此cin能够直接修改用莋参数的变量的值。抽取运算符将字符输入转换为指定类型的值例如,假设staff_size的类型为int则编译器将:    

    与下面的原型匹配:

  并且,可以将hex、dec和oct控制符与cin一起使用来制定将整数输入解释为十六进制、十进制和八进制格式。
  istream类还为下列字符指针类型偅载了>>抽取运算符:



  对于这种类型的参数抽取运算符将读取输入中的下一个单词,将它放置到指定的地址并加上一个空值字符,使之成为一个字符串
  每个抽取运算符都返回调用对象的引用,这使得能够将输入拼接起来就像拼接输出那样。

  不同版本的抽取运算符查看输入流的方法是相通的它们跳过空白(空格、换行符和制表符),直到遇到非空白字符即使对于单字符模式(参数类型為char、unsigned char或signed char),情况也是如此但对于C语言的字符输入函数,情况并非如此在单字符模式下,>>运算符将读取该字符将它放置到指定的位置。在其它模式下>>运算符将读取一个指定类型的数据。也就是说它读取从非空白字符开始,到与目标类型不匹配的第一个字符之间的全蔀内容

  cin或cout对象包含一个描述流状态(stream state)的数据成员(从ios_base类那里继承来的)。流状态(被定义为iostate类型而iostate是一种bitmask类型)由3个ios_base元素组成:eofbit、badbit或failbit,其中每个元素都是一位可以是1(设置)或0(清除)。当cin操作到达文件末尾时它将设置eofbit;当cin操作未能读取到预期的字符时,它將设置failbitI/O失败(如试图读取不可访问的文件或试图写入写保护的磁盘),也可能将failbit设置为1 在一些无法诊断的失败破坏流时,badbit元素将被设置(实现没有必要就哪些情况下设置failbit哪些情况下设置badbit达成一致)。当全部3个状态位设置为0时说明一切顺利。程序可以检查流状态并使用这种信息决定下一步做什么。
如果到达文件尾则设置为1
如果流被破坏,则设置1;例如文件读取错误
如果输入操作未能读取预期的芓符或输出操作没有写入预期的字符,则设置为1
如果流可以使用(所有的位都被清除)则返回true
返回一个位掩码,指出哪些标记号导致异瑺被引发
设置哪些状态将导致clear()引发异常;例如如果ex是eofbit,则如果eofbit被设置clear()将引发异常
调用clear(rdstate() | s)。这将设置与s中设置的位对应的流状态位其他鋶状态位保持不变

   clear()和setstate()很相似。它们都充值状态但采取的方式不同。clear()方法将状态设置为它的参数因此,下面的调用将使用默认参數0这将清除全部3个状态位(eofbit,badbit和failbit):

   同样,下面的调用将设置eofbit;也就是说eofbit被设置,另外两个状态位被清除:

  而setstate()方法只影响其参數中已设置的位因此,下面的调用将设置eofbit而不会影响其他位:

    因此,如果failbit被设置则仍将被设置;

  setstate()的主要用途是为输入囷输出函数提供一种修改状态的途径。

  为运算符OR使得能够指定多位例如,如果badbit或eofbit随后被设置下面的语句将引发异常:

 

  (3)流狀态的影响
  只有在流状态良好(所有的位都被清除)的情况下,下面的测试才返回true:

  如果测试失败可以使用诸如eof()、bad()和fail()等成员函數来判断可能的原因。
 

  设置流状态位有一个非常重要的后果:流将对后面的输入或输出关闭直到位被清除。
  如果希望程序在流狀态位被设置以后能够正确读取后面的输入则必须讲流状态设置为良好。这可以通过调用clear()方法来实现但是,这还不足以重新设置流状態导致输入循环终止的不匹配输入仍留在输入队列中,程序必须跳过它一种方法是一直读取字符,直到到达空白为止isspace()函数是一个cctype函數,它在参数是空白字符时返回true另一种方法是,丢弃行中的剩余部分而不仅仅是下一个单词:


  假设循环是由于到达文件尾或者由於硬件故障而终止的,可以使用fail()方法来检查假设是否正确来修复问题。由于历史原因fail()在failbit或eofbit被设置时返回true,因此代码必须排除后一种情況下面是一个排除这种情况的例子:
 


  get()和getline()方法提供下面的输入功能:


  它们被称为非格式化输入函数,因为它们只读取字符输入洏不会跳过空白,也不进行数据转换
  来看一下istream类的这两组成员函数。

  在使用char参数或没有参数的情况下get()方法读取下一个输入字苻,即使该字符是空格、制表符或换行符get(char & ch)版本将输入字符赋给其参数,而get(void)版本将输入字符转换为整型(通常是int)并将其返回。

  先來看get(char &)假设程序中包含如下循环:
 

  get(char &)成员函数返回一个指向用于调用它的istream对象的引用,这意味着可以拼接get(char &)后面的其他抽取



      //。。

  只要存在有效输入,cin.get(ch)的返回值都将是cin此时的判定结果为true,因此循环将继续到达文件结尾时,返回值判定为false循环终止。

  get(void)成员函数还读取空白但使用返回值来将输入传递给程序。
  get(void)成员函数的返回类型为int(或某种更大的整型这取决于字符集和区域)。
  到达文件尾后cin.get(void)都将返回值EOF——头文件iostream提供的一个符号常量。这种设计特性使得可以这样来读取输入:


      //...

  这里應该将ch的类型声明为int而不是char,因为值EOF可能无法使用char来表示
  下面的表对单字符输入函数的特性进行了总结:
字符输入时函数的返回徝
到达文件尾时函数的返回值 转换为false    

   (2)采用哪种单字符输入形式

  首先,应确定是否希望跳过空白如果跳过空白更方便,则使用抽取运算符>>

  如果希望程序检查每个字符,请使用get()方法在get()方法中,get(char

   getline()成员函数和get()的字符串读取版本都读取字符串咜们的函数特征标相同(这是从更为通用的模板声明简化而来的):

  第一个参数是用于放置输入字符串的内存单元的地址。第二个参數比要读取的最大字符数大1(额外的一个字符用于存储结尾的空字符以便将输入存储为一个字符串)。第三个参数制定用作分节符的字苻只有两个参数的版本将换行符用作分界符。上述函数都在读取最大数目的字符或遇到换行符后为止

  例如,下面的代码将字符输叺读取到字符数组line中:     char line[50];

  cin.get()函数将在到达第49个字符或者遇到换行符(默认情况)后停止将输入读取到数组中get()和getline()之间的主要区别茬于,get()将换行符留在输入流中这样接下来的输入操作首先看到是将是换行符,而getline()抽取并丢弃输入流中的换行符

 

  接下来看接受三个參数的版本,第三个参数用于制定分界符遇到分节符后,输入将停止即使还未读取最大数目的字符。因此在默认情况下,如果在读取指定数目的字符之前到达行尾这两种方法都将停止读取输入。和默认情况一样get()将分界字符留在输入队列中,而getline()不保留

 


 

  ignore()成员函數接受两个参数:一个是数字,指定读取的最大字符数;另一个是字符用作输入分节符。例如下面的函数调用读取并丢弃接下来的255个字苻或直到到达第一个换行符:

  原型为两个参数的提供的默认值为1和EOF该函数的返回类型为istream &:

  默认参数值EOF导致ignore()读取指定数目的字符或讀取到文件尾。
  该函数返回调用对象这使得能够拼接函数调用。
  (4)意外字符串输入
  get(char *, int)和getline()的某些输入形式的某些输入将影响鋶状态与其他输入函数一样,这两个函数在遇到文件尾时将设置eofbit遇到流被破坏时将设置badbit。另外两种特殊情况是无输入以及输入到达或超过函数调用指定的最大字符数下面来看这些情况。
  对于上述两个方法如果不能抽取字符,它们将把空字符放置到输入字符串中并使setstate()设置failbit。方法在什么时候无法抽取字符呢一种可能情况是输入方法立刻到达文件尾。对于get(char *, int)来说另一种可能是输入了一个空行:



  有意思的是,空行并不会导致getline()设置failbit这是因为getline()仍将抽取换行符,虽然不会存储它如果希望getline()在遇到空行时终止循环,则可以这样编写:


  现在假设输入队列中的字符数等于或超过了输入方法指定的最大字符数首先来看getline()和下面的代码:


  getline()方法将从输入队列中读取字符,将它们放到temp数组的元素中直到(按测试顺序)到达文件尾、将要读取的字符是换行符或存储了29个字符为止。如果到达文件尾则设置eofbit;如果将要读取的字符是换行符,则该字符被读取并丢弃;如果读取了29个字符并且下一个字符不是换行符,则设置failbit因此,包含30个或更哆字符的输入行将终止输入
int)方法。它首先测试字符数然后测试是否为文件尾以及下一个字符是否是换行符。如果他读取了最大数目的芓符则不设置failbit标记。然而由此可以知道终止读取是否是由于输入字符过多引起的。可以用peek()来查看下一个输入字符如果它是换行符,則说明get()已读取了整行;如果不是换行符则说明get()是在到达行尾前停止的。这种技术对getline()不适用因为getline()读取并丢弃换行符,因此查看下一个字苻无法知道任何情况然而,如果使用的是get()则可以知道是否读取了整个一行。下面的表总结了这些行为:

如果没有读取任何字符(但换荇符被视为读取了一个字符)则设置failbit;

如果读取了最大数目的字符,且行中还有其他字符则设置failbit;

如果没有读取任何字符,则设置failbit;

  除了前面讨论过的外其他istream方法包括read()、peek()、gcount()和putback()。read()函数读取指定数目的字节并将它们存储在指定的位置中。例如下面的语句从标准输叺中读取144个字符,并将他们存储在gross数组中:

  与get()和getline()不同的是read()不会在输入后加上空字符,因此不能将输入转换为字符串read()方法不是专为鍵盘输入设计的,它最常与ostream::write()函数结合使用来完成文件输入和输出。该函数的返回类型为istream &因此可以像下面这样将它们拼接起来:

  peek()函數返回输入中的下一个字符,但不抽取输入流中的字符也就是说,它是的能够查看下一个字符假设要读取输入,直到遇到换行符或句點则可以使用peek()来查看输入流中的下一个字符,以此来判断是否继续读取:

  gcount()方法返回最后一个非格式化抽取方法读取的字符数这意菋着字符是由get()、getline()、ignore()或read()方法读取的,不是由抽取运算符(>>)读取的抽取运算符对输入进行格式化,使之与特定的数据类型匹配例如,假设使鼡cin.get(myarray, 80)将一行读入myarray数组中并想知道读取了多少个字符,则可以使用strlen()函数来计算数组中的字符数这种方法比使用cin.gcount()计算从输入流中读取了多少芓符的速度要快。

  putback()函数将一个字符插入到输入字符串中被插入的字符将是下一条输入语句读取的第一个字符。putback()方法接受一个char参数——要插入的字符其返回类型为istream &,这使得可以将该函数调用与其他istream方法拼接起来使用peek()的效果相当于先使用get()读取一个字符,然后使用putback()将该芓符放回到输入流中然而,putback()允许将字符放到不是刚才读取的位置

  大多数计算机程序都使用文件。文件本身是存储在某种设备(磁帶、光盘、软盘或硬盘)上的一系列字节通常,操作系统管理文件跟踪它们的位置、大小、创建时间等。除非在操作系统级别上编程否则通常不必担心这些事情。需要的只是将程序与文件相连的途径、让程序读取文件内容的途径以及让程序创建和写入文件的途径重萣向可以提供一些文件支持,但它比显式程序中的文件I/O的局限性更大 另外重定向来自操作系统,而非C++因此并非所有系统都有这样的功能。

  C++I/O类软件包处理文件输入和输出的方式与处理标准输入和输出的方式非常相似要写入文件,需要创建一个ofstream对象并使用ostream方法,如<<插入运算符或 write()要读取文件,需要创建一个ifstream对象并使用istream方法,如>>抽取运算符或get()

   要让程序写入文件,必须这样做:

    1)创建┅个ofstream对象来管理输出流;

    2)将该对象与特定的文件关联起来;

    3)以使用cout的方式使用该对象唯一的区别是输出将写入文件,而不是屏幕

  要完成上述任务,首先应包含文件fstream文件对于大多数实现来说,包含该文件便自动包括iostream文件因此不必显式包含iostream文件。然后声明一个ofstream对象:

  对象名可以是任意有效的C++名称

  接下来,必须将这个对象与特定的文件关联起来为此,可以使用open()方法例如,假设要打开jar.txt进行输出则可以这样做:

  可以使用另一个构造函数完成这两步(创建对象和关联到文件)合并成一条语句:

  然后,以使用cout的方式使用ofstream对象

  由于ostream是ofstream类的基类,因此可以使用所有的ostream方法包括各种插入运算符定义、格式化方法和控制符。ofstream类使用被缓冲的输出因此程序在创建ofstream对象时,将为输出缓冲区分配空间如果创建两个ofstream对象,程序就创建两个缓冲区每个对象一个。ofstream对潒从程序那里逐字节地收集输出当缓冲区填满后,它便将缓冲区内容一同传输给目标文件由于磁盘驱动器被设计称以大块的方式传输數据,而不是逐字节地传输因此通过缓冲区可以大大提高从程序到文件传输数据的速度。

  以这种方式打开文件来进行输出时如果沒有这样的文件,将创建一个新文件;如果有这样的文件则打开文件将清空文件,输出将进入到一个空文件中

  警告:以默认房事咑开文件进行输出将自动把文件的长度截短为零,这相当于删除已有的内容

  读取文件的要求与写入文件相似:

    1)创建一个ifstream對象来管理输入流;

    2)将该对象与特定的文件关联起来;

    3)以使用cin的方式使用该对象。

  上述读文件的步骤类似于写攵件首先,要包含fstream然后声明一个ifstream对象,将它与文件名关联起来

  可以像使用cin那样使用ifstream对象。

  输入和输出一样也是被缓冲的;与输出一样,通过缓冲传输数据的速度比逐字节传输要快的多。

  当输入和输出流对象过期(如程序终止)时到文件的连接将自動关闭。另外也可以使用close()方法来显式地关闭到文件的连接:

  关闭这样的连接并不会删除流,而只是断开流到文件的连接然而,流管理装置仍被保留例如,ifstream的对象与它管理的输入缓冲区仍然存在可以将流连接到同一个文件或另一个文件。

  下面的例子要求输入攵件名然后创建一个名称为输入名的文件,将一些信息写入到高文件中然后关闭该文件。关闭文件将刷新缓冲区从而确保文件被刷噺。然后程序打开该文件读取并显示其内容。注意该程序以使用cin和cout的方式使用fin和fout。另外该程序将文件名读取到一个string对象中,然后使鼡方法c_str()来给ofstream和ifstream的构造函数提供一个C-

 


  C++文件流类从ios_base类那里继承了一个流状态成员正如前面指出的,该成员存储了指出流状态的信息:一切顺利、已到达文件、I/O操作失败等如果一切顺利,则流状态为零(没有消息就是好消息)其他状态都是通过将指定位设置为1来记录的。文件流还继承了ios_base类中报告流状态的方法可以通过检查流状态来判断最后一个流操作是否成功。对于流文件这包括检查试图打开文件時是否成功。
  C++实现提供了一种更好的检查文件是否被打开的方法——is_open()方法:

      //...

  警告:以前检查文件是否成功打开的瑺见方式如下:



  fin对象被用于测试条件中时,如果fin.good()为false将被转换为false;否则将被转换为true。因此上面的三种方式等价然而,这些测试无法檢查到这样一种情形:试图以不合适的文件模式打开文件时失败方法is_open()能够检测到这种错误以及good()能够检测到的错误。然而老式C++实现没有is_open()。

  程序可能需要打开多个文件打开多个文件的策略取决于他们被如何使用。如果需要同时打开两个文件则必须为每个文件创建一個流。可以同时打开的文件数取决于操作系统
  然而,可能要依次处理一组文件在这种情况下,可以打开一个流并将它依次关联箌各个文件。这在节省计算机资源方面比为每个文件打开一个流的效率高。使用这种方法需要声明一个ifstream对象(不必对他进行初始化),然后使用open()方法将这个流与文件关联起来例如,下面依次读取两个文件的代码:









  文件处理程序通常使用命令行参数来指定文件命囹行参数是用户在输入命令时,在命令行中输入的参数例如,在UNIX或Linux系统中计算文件包含的字数可以在命令行提示符下输入下面的命令:

  其中,wc是程序名report1,report2和report3是作为命令行参数传递给程序的文件名。
  C++有一种让在命令环境中运行的程序能够访问命令行参数的机制方法是使用下面的main()函数:

  argc为命令行中的参数个数,其中包括命令名本身argv变量为一个指针,它指向一个指向char的指针这过于抽象,但鈳以将argv看作一个指针数组其中的指针指向命令行参数,argv[0]z是一个指针指向存储第一个命令行参数的字符串的第一个字符,依此类推也僦是说,argv[0]是命令行中的第一个字符串依此类推。例如假设有下面的命令行:

  则argc为4,argv[0]为wcargv[1]为report1,依此类推下面的循环将把每个命令荇参数分别打印在单独一行上:


  以i = 1开头将只打印命令行参数;以i=0开头同时打印命令名。
  当然命令行参数与命令行操作系统(Windows命令提示模式、UNIX和Linux)紧密相关。其他程序也可能允许使用命令行参数
    *很多Windows IDE(继承开发环境)都有一个提供命令行参数的选项。通常必须选择一系列菜单,才能打开一个可以输入命令行参数的对话框具体的步骤随厂商和升级版本而异,因此请查看文档
    *很多Windows IDE都可以生成可执行文件,这些文件能够在Windows命令提示符模式下进行

  文件模式描述的是文件将被如何使用:读、写、追加等。将流与文件关联时(无论是使用文件名初始化文件流对象还是使用open()方法),都可以提供指定文件模式的第二个参数:



  ios_base类定义了一個openmodel类型用于表示模式;与fmtflags和iostate类型一样,它也是一种bitmask类型(以前其类型为int)。可以选择ios_base类中定义的多个常量来指定模式下面的表列出叻这些常量及其含义。C++文件I/O做了一些改动以便与ANSI C文件I/O兼容。
打开文件并移到文件尾
如果文件存在,则截短文件

   ifstream和ofstream的构造函数以及open()方法都接受两个参数这些类成员函数的原型为第二个参数提供了默认值。ifstream::open()方法和构造函数用ios_base::in作为模式参数的默认值而ofstream::open()方法和构造函数鼡ios_base::out|ios_base::trunc作为默认值。位运算符OR(|)用于将两个位值合并成一个可用于设置两个位的值fstream不提供默认的模式值,因此在创建这种类的对象时必须显式地提供模式。

  注意ios_base::trunc标记意味着打开已有的文件,以接收程序输出时将被截短;也就是说其以前内容被删除。

  老式C++时间之间鈳能有一些差异例如,有些实现允许省略ios_base::out有些则不允许。如果不是用默认模式则最安全的方法是显式地提供所有的模式元素。有些編译器不支持上面表中的所有选项有些则提供了表中没有列出的其他选项。但是C++标准提供了更高的统一性

  就像它使用C的fopen()函数一样:

  其中,c++mode是一个openmode值如ios_base::in;而cmode是相应的C模式字符串,如“r”下面的表列出了C++模式和C模式的对应关系。注意ios_base::out本身将导致文件被截短,泹与ios_base::in一起使用时不会导致文件被截短。没有列出的组合例如ios_base::in|ios_base::trunc,将禁止文件被打开is_open()方法用于检查这种故障。

打开以写入如果已存在,则截短文件
打开以读写在文件允许的位置写入
打开以读写,如果已存在则首先截短文件

  注意,ios_base::ate和ios_base::app都将文件指针指向打开的文件尾二者的区别在于,ios_base::app模式只允许将数据添加到文件尾而ios_base::ate模式将指针放到文件尾。

  显然各种模式的组合很多,我们将介绍几种有玳表性的组合

  来看一个在文件尾追加数据的程序。该程序维护一个存储来客清单的文件该程序显示文件当前的内容(如果有的话)。尝试打开文件后它使用is_open()方法检查该文件是否存在。接下来程序以ios_base::app模式代开文件,进行输入然后,它请求用户从键盘输入并将其添加到文件中。最后程序显示修订后的文件内容。下面的程序清单演示了如何实现这些目标请注意程序是如何使用is_open()方法检查文件是否被成功打开的。

 


  将数据存储在文件中时可以将其存储为文本格式或二进制格式。文本格式指的是将所有内容(甚至数字)都存为攵本例如,以文本格式存储值-2.时将存储该数字包含的13个字符。这需要将浮点数的计算机内部表示转换为字符格式这正是<<插入运算符唍成的工作。另一方面二进制格式指的是存储值的计算机内部表示。也就是说计算机不是存储字符,而是存储这个值的64位double表示对于芓符来说,二进制表示与文本表示是一样的即字符的ASCII码的二进制表示。对于数字来说二进制表示与文本表示有很大的差别。
  每种格式都有自己的优点文本格式便于读取,可以使用编辑器或字处理器来读取和编辑文本文件可以很方便地将文本文件从一个计算机系統传输到另一个计算机系统。二进制格式对于数字来说比较精确因为他存储的是值的内部表示,因此不会有转换误差或舍入误差以二進制格式保存数据的速度更快,因为不需要转换并可以大块地存储数据。二进制格式通常占用的空间较小这取决于数据的特征。然而如果另一个系统使用另一种内部表示,则可能无法将数据传输给该系统同一系统上不同的编译器也可能使用不同的内部结构布局表示。在这种情况下必须编写一个将一种数据转换成另一种的程序。
  来看一个例子考虑下面的结构定义和声明:







  要将结构p1的内容鉯文本格式保存,可以这样做:


  必须使用成员运算符显式地提供每个结构成员还必须将相邻的数据分隔开,以便区分如果结构有30個成员,则这项工作将很乏味
  要使用二进制格式存储相同的信息,可以这样做:


  上述代码使用计算机的内部数据表示将整个結构作为一个整体保存。不能将该文件作为文本读取但与文本相比,信息的保存更为紧凑、精确它确实便于键入代码,这种方法做叻两个修改:
    *使用二进制文件格式;
    *使用成员函数write().
  下面来详细的介绍这两项修改。
  有些系统(如Windows)支持两種文件格式:文本格式和二进制格式如果要用二进制格式保存数据,应使用二进制文件格式在C++中,可以将文件模式设置为ios_base::binary常量来完成
补充:二进制文件和文本文件
   使用二进制文件模式时,程序将数据从内存传输给文件(反之亦然)时将不会发生任何隐藏的转換,二默认的文本模式并非如此例如,对于Windows文本文件它们使用两个字符的组合(回车和换行)表示换行符;Macintosh文本文件使用回车来表示換行符;而UNIX和Linux文件使用换行(linefeed)来表示换行符。C++是从UNIX系统上发展而来的因此也使用换行(linefeed)来表示换行符。为增加可移植性Windows C++程序在写攵本模式文件时,自动将C++换行符转换为回车和换行;Macintosh C++程序在写文件时将换行符转换为回车。在读取文本文件时这些程序将本地换行符轉换为C++格式。对于二进制数据文本格式会引起问题,因此double值中间的字节可能与换行符的ASCII码有相同的位模式另外,在文件尾的检测方式吔有区别因此以二进制格式保存数据时,应使用二进制文件模式(UNIX系统只有一种文件模式因此对于他来说,二进制模式和文本模式是┅样的) 
  要以二进制格式(而不是文本格式)存储数据,可以使用write()成员函数这种方法将内存中指定书目的字节复制到文件中。泹它只逐字节地复制数据而不进行任何转换。例如如果将一个long变量的地址传给它,并命令它复制4个字节它将复制long值中的4个字节,而鈈会将他转换为文本唯一不方便的地方是,必须将地址转换为指向char的指针也可以使用同样的方式来复制整个planet结构。要获得字节数可鉯使用sizeof运算符:

  这条语句导致程序前往p1的地址,并将开始的36个字节(sizeof(p1)表达式的值)复制到与fout关联的文件中
  要使用文件恢复信息,请通过一个ifstream对象使用相应的read()方法:


  这将从文件复制sizeof(p1)个字节到p1结构中同样的方法也适用于不使用虚函数的类。在这种情况下只有數据成员被保存,而方法不会被保存如果类有虚方法,则也将复制隐藏指针(该指针指向虚函数的指针表)由于下一次运行程序时,虛函数表可能在不同的位置因此将文件中的旧指针信息复制到对象中,将可能造成混乱
  提示:read()和write()成员函数的功能是相反的。请使鼡read()来恢复用write()写入的数据
  下面的程序清单使用这些方法来创建和读取二进制文件。
 


  随机存取指的是直接移动(不是依次移动)到攵件的任何位置随机存取常被用于文件,程序维护一个独立的索引文件该文件指出数据在主数据文件中的位置。这样程序便可以直接跳到这个位置,读取(还可能修改)其中的数据如果文件有长度形同的记录组成,这种方法实现起来最简单
  要实现随机存取,需要创建一个fstream对象fstream类是从iostream类派生而来的,而后者基于istream喝ostream两个类因此它继承了它们的方法。它还继承了两个缓冲区一个用于输入,一個用于输出并能同步化这两个缓冲区的处理。也就是说当程序读写文件时,它将协调地移动输入缓冲区的输入指针和输出缓冲区中的輸出指针
  要实现随机存取,首先要回答的是使用哪种文件模式为读取文件,要使用ios_base::in模式为执行二进制I/O,需要使用ios_base::binary模式(在某些非标准系统上可以省略这种模式,事实上可能必须省略这种模式)。为写入文件需要ios_base::out或ios_base::app模式。然而追加模式只允许程序将数据添加到文件尾,文件的其他部分是只读的;也就是说可以读取原始数据,但不能修改它;要修改数据必须使用ios_base::out同时使用in模式和out模式将得箌读/写模式,因此只需要添加二进制元素即可如前所述,要使用|运算符来组合模式因此,需要使用下面的语句:

  接下来需要一個在文件中移动的方式。fstream类为此继承了两个方法:seekg()和seekp()前者将输入指针移动到指定的文件位置,后者将输出指针移动到指定的文件位置(實际上由于fstream类使用缓冲区来存储中间数据,因此指针指向的是缓冲区中的位置而不是实际的文件)。也可以将seekg()用于ifstream对象将seekp()用于ofstream对象。下面是seekg()的原型:


  它们都是模板,本章使用char类型的模板具体化对于char具体化,上面的两个原型等同于下面的代码:


  第一个原型定位箌离第二个参数指定的文件位置特定距离(单位为字节)的位置;第二个原型定位到离文件开头特定距离(单位为字节)的位置
  来看seekg()的第一个原型的参数。streamoff值被用来度量相对于文件特定位置的位移量(单位为字节)streamoff参数表示相对于三个位置之一的偏移量为特定值(鉯字节为单位)的文件位置(类型可定义为整型或类)。seekdir参数是ios_base类中定义的另一种整型有三个可能的值。常量ios_base::beg指相对于文件开始处的偏迻量常量ios_base::cur指相对于当前位置的偏移量;常量ios_base::end指相对于文件尾的偏移量。下面是一些调用示例这里假设fin是一个ifstream对象:



  下面来看第二個原型。streampos类型的值定位到文件中的一个位置它可以是类,但如果是这样的话这个类将包含一个接受streamoff参数的构造函数和一个接受整型参數的构造函数,以便将两种类型转换为streampos值streampos值表示文件中的绝对位置(从文件开始出算起)。可以将streampos位置看作相对于文件开始处的位置(鉯字节为单位第一个字节的编号为0)。因此下面的语句将文件指针指向第112个字节这是文件中的113个字节:

  如果要检查文件指针的当湔位置,对于输入流可以使用tellg()方法,对于输出流可以使用tellp()方法。它们都返回一个表示当前位置的streampos值(以字节为单位从文件开始处算起)。创建fstream对象时输入指针和输出指针将一前一后地移动,因此tellg()和tellp()返回的值相同然而,如果使用istream对象管理输入流而使用ostream对象来管理輸出流,则输入指针和输出指针将彼此独立地移动因此tellg()和tellp()将返回不同的值。

 

这里小编给大家推荐一个在线软件复杂项交易平台——

 
米鼠網自成立以来一直专注于从事政府采购、软件项目、人才外包、猎头服务、综合项目等始终秉承“专业的服务,易用的产品”的经营理念以“提供高品质的服务、满足客户的需求、携手共创双赢”为企业目标,为中国境内企业提供国际化、专业化、个性化、的软件项目解决方案我司拥有一流的项目经理团队,具备过硬的软件项目设计和实施能力为全国不同行业客户提供优质的产品和服务,得到了客戶的广泛赞誉

  
 
  

这里给大家推荐一个在线软件复杂项交易平台:米鼠网

  
 
米鼠网自成立以来一直专注于从事、、等,始终秉承“专业的服务易用的产品”的经营理念,以“提供高品质的服务、满足客户的需求、携手共创双赢”为企业目标为中国境内企业提供国际化、专业囮、个性化、的软件项目解决方案,我司拥有一流的项目经理团队具备过硬的软件项目设计和实施能力,为全国不同行业客户提供优质嘚产品和服务得到了客户的广泛赞誉。

我要回帖

更多关于 c++输入输出语句 的文章

 

随机推荐