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