c++的输入输出


c++的输入输出

​ C ++ I / O发生在流中,它们是字节序列。如果字节从键盘,磁盘驱动器或网络连接等设备流向主存储器,则称为输入操作,如果字节从主存储器流向显示屏幕,打印机,磁盘驱动器,或网络连接等,这称为输出操作

I / O库头文件

以下头文件对C ++程序很重要:

标题文件 功能和说明
<iostream> 该文件分别定义了对应于标准输入流,标准输出流,未缓冲标准错误流和缓冲标准错误流的cin,cout,cerrclog对象。
<iomanip> 该文件声明服务对于使用所谓的参数化流操作器(如setwsetprecision)执行格式化I / O是有用的。
<fstream> 该文件声明用于用户控制文件处理的服务。我们将在文件和流相关章节中详细探讨。

一、c++的输入

1.基本输入

标准输入流(cin)

​ 预定义的对象 ciniostream 类的一个实例。cin 对象附属到标准输入设备,通常是键盘。cin 是与流抽取运算符 >> 结合使用的,抽取运算符的一个特点就是跳过空白符(空格,换行符,制表符),如下所示:

#include <iostream>
 
using namespace std;
 
int main( ) {
   char name[50];
 
   cout << "Please enter your name: ";
   cin >> name;
   cout << "Your name is: " << name << endl;
 
}

当上面的代码被编译和执行时,它会提示用户输入名称。当用户输入一个值,并按回车键,就会看到下列结果:

Please enter your name: cplusplus
Your name is: cplusplus

​ C++ 编译器根据要输入值的数据类型,选择合适的流提取运算符来提取值,并把它存储在给定的变量中。
例子:使用cin输入

#include <iostream>

using std::cin;
using std::cout;
using std::endl;


int main(){
    int hc;
    cout<<"Please enter your handicap:"<<endl;
    // 如果输入的值与变量hc类型不一致,则cin >> hc返回false
    while (!(cin >> hc)){

        cin.clear();
        // 去除多余的错误字符
        while (cin.get() != '\n')
            continue;
        cout << "Error!, Please enter your handicap:";

    }
    cout << "hc:" << hc <<endl;
}

流提取运算符 >> 在一个语句中可以多次使用,如果要求输入多个数据,可以使用如下语句:

cin >> name >> age;

这相当于下面两个语句:

cin >> name;
cin >> age;

标准错误流(cerr)

​ 预定义的对象 cerriostream 类的一个实例。cerr 对象附属到标准错误设备,通常也是显示屏,但是 cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。

cerr 也是与流插入运算符 << 结合使用的,如下所示:

#include <iostream>
 
using namespace std;
 
int main( ) {
   char str[] = "Unable to read....";
 
   cerr << "Error message : " << str << endl;
}

当上述代码被编译并执行时,它产生以下结果:

Error message : Unable to read....

标准日志流(clog)

​ 预定义的对象 clogiostream 类的一个实例。clog 对象附属到标准错误设备,通常也是显示屏,但是 clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲区,直到缓冲填满或者缓冲区刷新时才会输出。

clog 也是与流插入运算符 << 结合使用的,如下所示:

#include <iostream>
 
using namespace std;
 
int main( ) {
   char str[] = "Unable to read....";
 
   clog << "Error message : " << str << endl;
}

当上述代码被编译并执行时,它产生以下结果:

Error message : Unable to read....

​ 通过这些小实例,我们无法区分 cout、cerr 和 clog 的差异,但在编写和执行大型程序时,它们之间的差异就变得非常明显。所以良好的编程实践告诉我们,使用 cerr 流来显示错误消息,而其他的日志消息则使用 clog 流来输出。

2.其他istream类方法

除了各种operator>>()函数(跳过空白符)外,istream类还提供了get()方法和getline()方法。

  • 方法get{char&)和get(void)提供不跳过空白符的单字符输入功能;

  • 函数get(char,int, char)和getline(char,int, char)在默认情况下读取整行而不是一个单词。

    它们被称为非格式化输入函数,因为它们只是读取字符输入,而不会跳过空白符,也不进行数据转换。

2.1 单字符输入

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

备注:空格、制表符或换行符都是指空白符。

(1)成员函数 cin.get(char &)

#include <iostream>

int main()
{
    using std::cout;
    using std::endl;
    int ct = 0;
    char ch;
    cin.get(ch);
    while (ch != '\n')
    {
        cout << ch;
        ct++;
        cin.get(ch);
    }
    cout << ct << endl;
}

运行以上程序,提供以下输入:

I C++ clearly.<Enter>

​ 按下回车键后,这行输入将被发送给程序。上述程序片段将首先读取字符I,使用cout显示它,并将ct递增到1。接着,它读取I后面的空格字符,显示它,并将ct递增到2。这一过程将一直继续下去,直到程序将回车键作为换行符处理,并终止循环。这里的重点是,通过使用get(ch),代码读取、显示并考虑空格和可打印字符。
假设程序试图使用>>:

#include <iostream>

int main()
{
    using std::cout;
    using std::endl;
    int ct = 0;
    char ch;
    cin >> ch;
    while (ch != '\n') // FAILS
    {
        cout << ch;
        ct++;
        cin >> ch;
    }
    cout << ct << endl;
}

则代码将首先跳过空格,这样将不考虑空格,因此相应的输出压缩为:

IC++clearly.

更糟糕的是,循环不会终止!由于抽取运算符跳过了换行符,因此代码不会将换行符赋给ch,所以while循环测试将不会终止循环。

(2)成员函数 cin.get(void)

get(void)成员函数还读取空白符,但使用返回值来将输入传递给程序。因此可以这样使用它:

#include <iostream>

int main()
{
    using std::cout;
    using std::endl;
    int ct = 0;
    char ch;
    cin.get(); // use return value
    while (ch != '\n')
    {
        cout << ch;
        ct++;
        cin.get();
    }
    cout << ct << endl;
}

get(void)成员函数的返回类型为int(或某种更大的整型,这取决于字符集和区域)。这使得下面的代码是非法的:

char c1,c2,c3
cin.get().get() >> c3; // not valid

可改成:

char c1
cin.get(c1).get(); // valid

因为cin.get(c1)返回cin对象,因此它可以放在get()的前面。

image-20210608190035667

(3)get(char &) 与 get()到达文件尾的判定

​ 文件尾是指:真正的文件尾以及通过键盘仿真的文件尾(对于DOS和Windows命令提示符模式,为按下Ctrl + Z;对于UNIX,是在行首按Ctrl + D)

get(char &)

char ch;
while(cin.get(ch))
{
	//process input
}

get(void)

int ch;
while((ch=cin.get())!=EOF)
{
	//process input
}

注:这里应将ch的类型声明为int,而不是char,因为值EOF可能无法使用char类型来表示。

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

​ 首先,应确定是否希望跳过空白。如果跳过空白更为方便,则使用抽取运算符>>。例如,提供一菜单选项时,跳过空白更为方便;

​ 如果希望程序检查每个字符,请使用get()方法,例如,计算字数的程序可以使用空格来判断单词何时结束。在get()方法中,get(char &)的接口更佳。

​ get(void)的主要优点是,它一与标准C语言中的getchar()函数极其类似,这意味着可以通过包含iostream(而不是stdio.h ),并用cin.get()替换所有的getchar(),用cout.put(ch)替换所有的putchar(ch),来将c程序转换为c++程序。

2.2 字符串输入:getline()、get()和ignore()

(1)get()与getline()

函数原型

istream &   get(char *, int, char)

istream &  get(char *, int)

istream &   getline(char *, int, char)

istream &  getline(char *, int)

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

例如,下面的代码将字符输入读取到字符数组line中:

char line[50];
cin.get(line,50);

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

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

(2)ignore()

函数原型

istream &  ignore(int=1, int=EOF)

原型为两个参数提供的默认值为l和EOF,该函数的返回类型为istream &.默认参数值EOF导致ignore()读取指定数目的字符或读取到文件尾。

该函数返回调用对象,这使得能够拼接函数一调用,如下所示:

cin.ignore(255, '\n').ignore(255, '\n')

​ 其中,第一个ignore()方法读取并丢弃一行,第二个调用读取并丢弃另一行,因此一共读取了两行。

以下程序演示了getline()、get()和ignore()是如何工作的。

#include <iostream>
const int Limit = 255;

int main()
{
    using std::cout;
    using std::cin;
    using std::endl;

    char input[Limit];

    cout << "Enter a string for getline() processing:\n";
    cin.getline(input, Limit, '#');
    cout << "Here is your input:\n";
    cout << input << "\nDone with phase 1\n";

    char ch;
    cin.get(ch);
    cout << "The next input character is " << ch << endl;

    if (ch != '\n')
        cin.ignore(Limit, '\n');    // discard rest of line

    cout << "Enter a string for get() processing:\n";
    cin.get(input, Limit, '#');
    cout << "Here is your input:\n";
    cout << input << "\nDone with phase 2\n";

    cin.get(ch);
    cout << "The next input character is " << ch << endl;
/* keeping output window open */
/*
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
*/
    return 0; 
}

输出结果:

Enter a string for getline() processing:
Please pass
me a #3 melon!
Here is your input:
Please pass
me a
Done with phase 1
The next input character is 3
Enter a string for get() processing:
I still
want my #3 melon!
Here is your input:
I still
want my
Done with phase 2
The next input character is #

注意,getline( )函数将丢弃输入中的分界字符#,而get()函数不会。

(3)意外字符串输入

​ get(char*,int)和getline()的某些输入形式将影响流状态。与其他输入函数一样,这两个函数在遇到文件尾时将设置eofbit,遇到流被破坏(如设备故障)时将设置badbit。另外两种特殊情况是无输入以及输入到达或超过函数调用指定的最大字符数。下面来看这些情况。

我们重点讲一下无输入,即空行和超过函数调用指定的最大字符数这两种情况。

a.空行

get()捕获到空行,则会终止循环:

char tmp[80];
while(cin.get(tmp, 80)) // 遇到空行终止循环
  ...

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

char tmp[80];
while(cin.getline(tmp, 80) && tmp[0] != '\0') // 遇到空行终止循环
  ...

b.超过函数调用指定的最大字符数

char tmp[30];
while(cin.getline(tmp, 30))

​ getline( )方法将从输入队列中读取字符,将它们放到hemp数组的元素中,直到(按测试顺序)到达文件尾、将要读取的字符是换行符或存储了29个字符为止。

  • 遇到文件尾,则设置eoibit:
  • 读取是换行符,则该字符将被读取并丢弃;
  • 读取了29个字符,并且下一个字符不是换行符,则设置failbit。

因此,包含30个或更多字符的输入行将终止输入。

​ 现在来看get(char *, int)方法。它首先测试字符数,然后测试是否为文件尾以及下一个字符是否是换行符。与getline( )方法不同的是,如果它读取了最大数目的字符,则不设置failbit标记。然而,由此可以知道终止读取是否是由于输入字符过多引起的。可以用peek()来查看下一个输入字符。如果它是换行符,则说明get()已读取了整行;如果不是换行符,则说明get()是在到达行尾前停止的。

​ 这种技术对getline()不适用,因为getline ()读取并丢弃换行符,因此查看下一个字符无法知道任何情况。然而,如果使用的是get(),则知道是否读取了整个一行。以下表总结了这些行为:

没有读取任何字符(空行) 读取了最大数目的字符,但行中还有其他字符 文件尾 换行符/分隔符
getline(char *, int) 不设置failbit 设置failbit 设置eofbit 不设置failbit,读取空行或分界符并丢弃
getline(char *, int, char) 不设置failbit 设置failbit 设置eofbit 不设置failbit,读取空行或分界符并丢弃
get(char *, int) 设置failbit 不设置failbit 设置eofbit 设置failbit,读取空行或分界符不丢弃
get(char *, int, char) 设置failbit 不设置failbit 设置eofbit 设置failbit,读取空行或分界符不丢弃

(4)带参数的get()与不带参数的get(void)的配合使用

​ get()函数其中一个变体的工作方式与getline( )类似,它们接受的参数相同,解释参数的方式也相同,并且都读取到行尾。但get并不再读取并丢弃换行符,而是将其留在输入队列中。假设我们连续两次调用get( )

get(dessert,Arsize);
get(dessert,Arsize);//a problem

​ 由于第一次调用后,换行符将留在输入队列中,因此第二次调用时看到的第一个字符便是换行符。因此get()认为已到达行尾,而没有发现任何可读取的内容。如果不借助于帮助,get( )将不能跨过该换行符。
​ 幸运的是,get()有另一种变体。使用不带任何参数的cin.get()调用可读取下一个字符(即使是换行符),因此可以用它来处理换行符,为读取下一行输入做好准备。也就是说,可以采用下面的调用序列:

cin.get(dessert,Arsize); // reed first line
cin.get(); // read newline
cin.get(dessert,Arsize);//read second line

另一种使用get()的方式是将两个类成员函数拼接起来(合并),如下所示:

cin.get(name,Arsize).get(); //concatenate member functions

​ 之所以可以这样做,是由于cin.get(dessert,Arsize)返回一个cin对象,该对象随后将被用来调用get()函数。同样,下面的语句将把输入中连续的两行分别读入到数组name 1和name2中,其效果与两次调用cin .getline()相同(getline会读取并丢弃换行符):

cin.getline(name1,Arsize).getline(name2,Arsize); 

拓展:

如果用get()或者getline()读取整行数据,但因为超过函数调用指定的最大字符数,无法读取剩下的字符,则可利用get(void)方法进行多余字符的去除。

while(cin.get() != '\n')
{
    continue;
}

2.3 总结

cin.get()

返回值 参数 功能
istream& char*, int, char 第一个参数用于放入输入字符串的地址,第二个参数表示读取的最大字符数+1,第三个表示用作分界符的字符。返回对cin对象的引用。该函数读取到最大数目字符或遇到分界符为止。分界符留在输入流中
istream& char*, int 第一个参数用于放入输入字符串的地址,第二个参数表示读取的最大字符数+1。返回对cin对象的引用。该函数读取到最大数目字符或遇到换行符为止。换行符留在输入流中
istream& char& 读取一个字符赋给其参数。返回对cin对象的引用。即使该字符是空白符。
int 读取一个字符,将字符转化为整型,并将其返回。即使该字符是空白符。

getline()

函数 功能
istream&cin.getline(char*, int ,char) 第一个参数用于放入输入字符串的地址,第二个参数表示读取的最大字符数+1,第三个表示用作分界符的字符。返回对cin对象的引用。该函数读取到最大数目字符或遇到分界符为止。读取并丢弃分界符
istream&cin.getline(char*, int r) 第一个参数用于放入输入字符串的地址,第二个参数表示读取的最大字符数+1。返回对cin对象的引用。该函数读取到最大数目字符或遇到换行符为止。读取并丢弃换行符
getline(cin,string&) cin为标准输入流,第二个参数为string类。表示从标准输入流中读取到string对象中。该函数遇到换行符为止。读取并丢弃换行符

注:由于引入string类晚于istream类的引入,istream类设计时没有考虑到string类,故istream类中没有处理string的方法

3.其他istream方法

3.1 read()

read()函数读取指定数目的字节,并将他们存储在指定的位置上。

例如:

char gross[144];
cin.read(gross, 144) // 从标准输入中读取144个字符,并存储在gross数组中

​ 与getline()和get()不同的是,read()不会在输入后加上空值字符,因此不能将输入转换为字符串。read()方法不是专为键盘输入设计的,它常与ostream write()函数结合使用,来完成文件输入和输出。

3.2 peek()

peek()函数返回输入中的下一个字符,但不抽取输入流中的字符。

例子:

char great_input [80];
char ch;
int i = 0;
while((ch = cin.peek()) != '.' && ch != '\n')
  cin.get(great_input[i++]);
great_input [i] = '\0';

3.3 putback()

putback()函数将一个字符插入到输入字符串中。该方法接收一个char参数,并返回类型为istream &。

程序例子:

#include <iostream>

int main()
{
    using std::cout;
    using std::cin;
    using std::endl;

//  read and echo input up to a # character
    char ch;

    while(cin.get(ch))          // terminates on EOF
    {
        if (ch != '#')
            cout << ch;
        else
        {
            cin.putback(ch);    // reinsert character
            break;
        }
    }

    if (!cin.eof())
    {
        cin.get(ch);
        cout << endl << ch << " is next input character.\n";
    }
    else
    {
        cout << "End of file reached.\n";
        std::exit(0);
    }

    while(cin.peek() != '#')    // look ahead
    {
        cin.get(ch);
        cout << ch;
    }
    if (!cin.eof())
    {
        cin.get(ch);
        cout << endl << ch << " is next input character.\n";
    }
    else
        cout << "End of file reached.\n";
    return 0; 
}

测试结果:

输入:I used a #3 pencil when I should have used a #2.
输出:
I used a 
# is next input character.
3 pencil when I should have used a 
# is next input character.

程序中第一种方法是用while循环来读取输入:

while(cin.get(ch))          // terminates on EOF
{
  if (ch != '#')
    cout << ch;
  else
  {
    cin.putback(ch);    // reinsert character
    break;
  }
}

​ 达到文件尾时,表达式(cin.get(ch))将返回false,因此从键盘模拟文件尾将终止循环。如果#字符首先出现,则程序将该字符放回到输入流,并使用break语句来终止循环。

第二种方法看上去更简单:

while(cin.peek() != '#')    // look ahead
{
  cin.get(ch);
  cout << ch;
}

程序查看下一个字符,如果它不是#,则读取并显示它,然后再查看下一个字符。这一过程将一直继续下去,知道出现分界字符。

二、c++的输出

1.基本输出

标准输出流(cout)

​ 预定义对象coutostream类的一个实例。cout对象被称为“连接到”标准输出设备,通常是显示屏幕。的COUT用于在结合流插入操作符,其被写为<<其比迹象少两个如示于下述的例子。

#include <iostream>
 
using namespace std;
 
int main( ) {
   char str[] = "Hello C++";
 
   cout << "Value of str is : " << str << endl;
}

当上述代码被编译并执行时,它产生以下结果:

Value of str is : Hello C++

​ C ++编译器还确定要输出的变量的数据类型,并选择适当的流插入运算符来显示该值。<<运算符重载以输出内置类型的整数,浮点数,双精度,字符string和指针值的数据项。

​ 如上所示,插入运算符<<可以在单个语句中多次使用,并且endl用于在行尾添加新行。

2.其他ostream方法

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

put()方法

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

ostream&put(char);

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

  cout.put(’W’);// display the W character

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

~~~c++

cout.put(‘I’).put(‘t’);//displaying It
~~~

​ 函数调用cout.put('I')返回cout,cout 然后被用作Put('t')调用的调用对象。

write()方法

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

basic_ostream<charT,traits)& write(const char_type* s,streamsize n);

​ write()的第一个参数提供了要显示的字符串的地址,第二个参数指出要显示多少个字符。使用cout调用write()时,将调用char具体化,因此返回类型为ostream &。程序演示了write()方法是如何工作的。

// write.cpp -- using cout.write()
#include <iostream>
#include <cstring>  // or else string.h

int main()
{
    using std::cout;
    using std::endl;
    const char * state1 = "Florida";
    const char * state2 = "Kansas";
    const char * state3 = "Euphoria";
    int len = std::strlen(state2);
    cout << "Increasing loop index:\n";
    int i;
    for (i = 1; i <= len; i++)
    {
        cout.write(state2,i);
        cout << endl;
    }

// concatenate output
    cout << "Decreasing loop index:\n";
    for (i = len; i > 0; i--)
        cout.write(state2,i) << endl;

// exceed string length
    cout << "Exceeding string length:\n";
    cout.write(state2, len + 5) << endl;
    // std::cin.get();
    return 0; 
}

输出:

Increasing loop index:
K
Ka
Kan
Kans
Kansa
Kansas
Decreasing loop index:
Kansas
Kansa
Kans
Kan
Ka
K
Exceeding string length:
Kansas  Eup

​ 需要注意的是,write()方法并不会在遇到空字符时自动停止打印字符,而只是打印指定数目的字符,即使超出了字符串的边界!在这个例了中,在字符串" Kansas”的前后声明了另外两个字符串,以便相邻的内存包含数据。编译器在内存中存储数据的顺序以及调整内存的方式各不相同。例如,"Kansas”占用6
个字节,而该编译器使用4个字节的倍数调整字符串,因此“Kansas”被填充成占用8个字节。由于编译器之间的差别,因此输出的最后一行可能不同。
​ write()方法也可用于数值数据,您可以将数字的地址强制转换为char,然后传递给它:

long val = 560031841;
cout.write( (char*) &va1,sizeof(long));

​ 这不会将数字转换为相应的字符,而是传输内存中存储的位表示。例如,4字节的long值(如560031841)将作为4个独立的字节被传输。输出设备(如显示器)将把每个字节作为ASCII码进行解释。因此在屏幕上,560031841将被显示为4个字符的组合,这很可能是乱码(也可能不是,请试试看)。然而,write()确实为将数值数据存储在文件中提供了一种简洁、准确的方式。

3.setf函数的使用

​ setf()函数的功能是使用控制符控制输出格式,相反,unset()函数则是取消控制符控制输出格式。

它有两个原型,分别是:

fmtflags setf(fmtflage) //第一原型
fmtflags setf(fmtflags, fmtflags)  //第二原型
//fmtflags 是 bitmask 类型,是一种用来存储各个位值的类型。它可以是整型、枚举、也可以是STL bitset容器。iostream软件包使用bitmask来存储状态信息。
//显而易见,两个原型的主要区别在于参数数量不同

下面详细介绍 setf() 的两个原型的使用:

setf()的第一原型:
C++为标准输入和输出定义了一些格式标志, 它可以通过flags(), setf(), 和 unsetf() 三个函数来控制.
例如:

cout.setf(ios_base::showpos); //对所有cout的输出进行正数前面加上+

举例演示:

//showpos内部调用cout.setf(ios_base::showpos)

// 形式一:
// cout << showpos << 255 << endl;

// 形式二:
// showpos(cout);
// cout << 255 << endl;

// 形式三:
cout.setf(ios_base::showpos);
cout << 255 << endl;
//输出: +255

//scientific内部调用cout.setf(ios_base::scientific)

// 形式一:
// cout << scientific << 255.255 << endl;

// 形式二:
// scientific(cout);
// cout << 255.255 << endl;

// 形式三:
cout.setf(ios_base::scientific);
cout << 255.255 << endl;
//输出: 2.55255e+02

一些常见的格式常量:

image-20210608095847738

setf()的第二原型:

​ 第二原型包含两个参数,第一个参数和第一原型里的参数一样,第二个参数指出要清除第一参数中的哪些位,也就是说,在第二原型中,第一个参数指出要设置哪些位,第二个参数指出要清除哪些位。

​ 虽然听起来很麻烦,但实际上用起来却很简单,只需按自己的实际需求在下表中找到对应的参数套上去就可以了。

image-20210608095001680

三、头文件iomanip

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

iomanip 中定义的操作符:

操作符 描述 输入 输出
setiosflags(long f) 启用指定为f的标志
resetiosflags(long f) 关闭被指定为f的标志
setbase(int base) 设置数值的基本数为base
setfill(int ch) 设置填充字符为ch
setprecision(int p) 设置数值的精度(四舍五入)
setw(int w) 设置域宽度为w

以下程序演示了这一点,它对于每一行输出,都多次修改了字段宽度和填充字符,同时使用了一些较新的标准控制符。

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
    using namespace std;
    // use new standard manipulators
    cout << fixed << right;

    // use iomanip manipulators
    cout << setw(6) << "N" << setw(14) << "square root"
         << setw(15) << "fourth root\n";

    double root;
    for (int n = 10; n <=100; n += 10)
    {
        root = sqrt(double(n));
        cout << setw(6) << setfill('.') << n << setfill(' ')
               << setw(12) << setprecision(3) << root
               << setw(14) << setprecision(4) << sqrt(root)
               << endl;
    }
	// std::cin.get();
    return 0; 
}

输出:

     N   square root   fourth root
....10       3.162        1.7783
....20       4.472        2.1147
....30       5.477        2.3403
....40       6.325        2.5149
....50       7.071        2.6591
....60       7.746        2.7832
....70       8.367        2.8925
....80       8.944        2.9907
....90       9.487        3.0801
...100      10.000        3.1623

四、标准控制符

使用setf()不是进行格式化的、对用户最为友好的方法,c++提供了多个控制符,能够调用setf(),并自动提供正确的参数。

比如使用cout<<left;相当于调用cout.setf(ios_base::left, ios_base::adjustfield).

1.iostream 中定义的控制符

控制符 调用 描述 输入 输出
endl 输出换行标示,并清空缓冲区
ends 输出空字符
flush 清空流
boolalpha setf(ios_base::boolalpha) 启用boolalpha标志
noboolalpha unset(ios_base::noboolalpha) 关闭boolalpha 标志
showbase setf(ios_base::showbase) 启用 showbase 标志
noshowbase unset(ios_base::showbase) 关闭showbase 标志
showpoint setf(ios_base::showpoint) 启用 showpoint 标志,显示小数点和额外的零,即使不需要.
noshowpoint unset(ios_base::showpoint) 关闭showpoint 标志
showpos setf(ios_base::showpos) 启用 showpos 标志,在非负数值前面显示”+(正号)”.
noshowpos unset(ios_base::showpos) 关闭showpos 标志
skipws 启用 skipws 标志,当从一个流进行读取时,跳过空白字符(spaces, tabs, newlines).
noskipws 关闭skipws 标志
unitbuf 启用 unitbuf 标志,在每次插入以后,清空缓冲区.
nounitbuf 关闭unitbuf 标志
uppercase setf(ios_base::uppercase) 启用 uppercase 标志,以大写的形式显示科学记数法中的”e”和十六进制格式的”x”.
nouppercase unset(ios_base::uppercase) 关闭uppercase 标志
ws 跳过所有前导空白字符
left setf(ios_base::left, ios_base::adjustfield) 启用 left 标志,输出调整为左对齐.
right setf(ios_base::right, ios_base::adjustfield) 启用 right 标志,输出调整为右对齐.
fixed setf(ios_base::fixed, ios_base::floatfield) 启用fixed标志,用正常的记数方法显示浮点数(与科学计数法相对应).
scientific setf(ios_base::scientific, ios_base::floatfield) 启用 scientific 标志,用科学记数法显示浮点数.
internal setf(ios_base::internal, ios_base::adjustfield) 启用 internal 标志,将填充字符回到符号和数值之间.
oct setf(ios_base::oct, ios_base::basefield) 启用 oct 标志,用8进制格式显示数值.
hex setf(ios_base::hex, ios_base::basefield) 启用 hex 标志,用16进制格式显示数值.
dec setf(ios_base::dec, ios_base::basefield) 启用dec标志,用10进制格式显示数值.

例子1:

//showpos内部调用cout.setf(ios_base::showpos)

// 形式一:
// cout << showpos << 255 << endl;

// 形式二:
// showpos(cout);
// cout << 255 << endl;

// 形式三:
cout.setf(ios_base::showpos);
cout << 255 << endl;
//输出: +255

例子2:

#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    cout<<setiosflags(ios::left|ios::showpoint);  // 设左对齐,以一般实数方式显示
    cout.precision(5);       // 设置除小数点外有五位有效数字 
    cout<<123.456789<<endl;
    cout.width(10);          // 设置显示域宽10 
    cout.fill('*');          // 在显示区域空白处用*填充
    cout<<resetiosflags(ios::left);  // 清除状态左对齐
    cout<<setiosflags(ios::right);   // 设置右对齐
    cout<<123.456789<<endl;
    cout<<setiosflags(ios::left|ios::fixed);    // 设左对齐,以固定小数位显示
    cout.precision(3);    // 设置实数显示三位小数
    cout<<999.123456<<endl; 
    cout<<resetiosflags(ios::left|ios::fixed);  //清除状态左对齐和定点格式
    cout<<setiosflags(ios::left|ios::scientific);    //设置左对齐,以科学技术法显示 
    cout.precision(3);   //设置保留三位小数
    cout<<123.45678<<endl;
    return 0; 
}

测试输出结果:

123.46
****123.46
999.123
1.235e+02

其中 cout.setf 跟 setiosflags 一样,cout.precision 跟 setprecision 一样,cout.unsetf 跟 resetiosflags 一样。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM