c++ 輸入輸出流 緩沖區 概述

c++的輸入輸出不是建立在語言上的,而是由iostreamfstream文件中定義的一組模板類實現的,且這個類庫不是正式語言定義的組成部分,就是說cin,cout等并不是語言的關鍵字.

流和緩沖區

c++把輸入輸出看作是字節流,輸入時,程序從輸入流中截取(>>)字符,輸出時,程序將字節插入(<<)到輸出流.通過這樣的方式,流就相當于連接輸入端和輸出端的一個橋梁,兩端只需要關聯到相應的流上即可實現連接,這樣處理輸入輸出的方式將獨立與流的去向.
如下圖所示:

緩沖區是指用作中介的內存塊,主要作用是用來提高處理輸入輸出的效率.原因在于像磁盤驅動器這樣的設備通常是以512字節的塊為單位來傳輸信息,而程序每次只能處理一個字節.所以通過緩沖的方法,一次從磁盤讀取大量的信息存儲到緩沖區,程序再從緩沖區中每次讀取一個字節,因為從內存中讀取一個字節的時間要遠小于從磁盤讀取的時間.

c++I/O文件

各個I/O類的繼承關系如下圖所示:

  • ios_basic類表示流的一般特性,如是否可讀取,是二進制流還是文本流.以及獨立于類型的一些特性.
  • streambuf類為緩沖區提供內存并提供了用于填充緩沖區,訪問緩沖區內容,刷新緩沖區,管理緩沖區等的方法
  • ios類繼承與ios_basic類并且包含了一個指向streambuf的指針成員.
  • ostream類繼承自ios類并提供了輸出方法
  • istream類繼承自ios類并提供了輸入方法
  • iostream類多繼承于istreamostream

在程序中包含iostream文件將自動創建8個流對象,4個窄字符流,4個寬字符流:

  • cin默認關聯標準輸入設備,wcin與此類似,用于處理wchar_t類型
  • cout默認關聯到標準輸出設備,wcout與此類似,用于處理wchar_t類型
  • cerr對應標準錯誤流,默認關聯到標準輸出設備,這個流沒有緩沖機制,wcerr....
  • clog也對應標準錯誤流,但是這個流有緩沖機制,wclog....

如上所知,c++的以上幾個對象就代表了c++的輸入輸出流.所以在流對象中就包含了與輸入輸出有關信息的數據成員,如顯示數據時使用的字段寬度,小數位數等...

重定向

由上面流的概述可知流只是充當連接輸入端和輸出端的一個橋梁而已.所以我們就可以通過改變流的流向來實現輸入輸出的重定向功能.

  • 標準輸入重定向 <
  • 標準輸出重定向 >
  • 標準錯誤重定向 2>

假設我們有一個程序counter從鍵盤接受輸入字符,并返回輸入字符的個數.那么我們只需如下就可以讓counter從文件input.txt中輸入字符,并把結果存到res.txt中:

counter <input.txt >res.txt

cout進行輸出

ios_basic類中存儲了描述格式狀態的信息,如計數系統,字段寬度,小數位數等,并提供了控制符來控制顯示整數時的計數系統,由于ios_basic類是ostream類的間接基類,所以可在ostream類的對象中直接使用.例如,要控制整數以十進制,十六進制,八進制顯示可分別使用dec,hex,oct控制符.
hex(cout); // 控制符不是成員函數,不必通過對象調用
進行如上設置后,cout將以十六進制顯示,直到將格式設置為其他選項為止.因為ostream重載了<<,所以一般以cout<<hex;方式單獨使用控制符.
ps: 對于cin,以上控制符也是可用的,表示以什么進制解釋輸入的整數

字段寬度

使用成員函數width()可實現將長度不同的數字放到寬度相同的字段中.原型為:

int width();      // 返回字段寬度的當前設置
int width(int i); // 將字段寬度設置為i并返回設置之前的字段寬度

注意: width()函數只影響接下來的一個項目,之后字段將恢復到默認值

填充字符

默認的cout使用空格填充字段中未被使用的部分,可使用成員函數fill(char)可改變填充字符.與字段寬度設置不同的是它會一直有效直到更改為止.

設置浮點數顯示精度

已知c++默認精度是6位,但末尾的0不顯示.可以使用成員函數precision(int)來設置顯示的精度,也就是數據的總位數.與fill()類似,一旦設置就一直有效直到被更改.
有時輸出需要顯示末尾的0和小數點,ostream類本身沒有提供這方面的函數,它的基類ios_basic類提供的成員函數setf()可以實現控制多種格式化特性,
使用setf()函數需要進行很多設置,用到很多的ios_basic的類級靜態常量,不是很友好.c++在頭文件iomanip中提供了其他一些控制符可以更方面的實現格式化特性.如下給出三個最常用的控制符:

  • setpricision(int): 設置精度
  • setfill(char): 設置填充字符
  • setw(int): 設置字段寬度

舉例如下:

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

int main()
{
    std::cout << std::fixed << std::right; // 顯示m末尾的0; 右對齊
    std::cout << std::setprecision(4);     // 設置顯示精度,一直有效

    std::cout << std::setw(6) << "N" << std::setw(15) << "squre root" << std::setw(15) << "fourth root" << std::endl;
    for (int i=10; i<=100; i+=10)
    {
                    // 設置字段寬度(只對下一條輸出內容有效)和填充字符(一直有效)
        std::cout   << std::setw(4) << std::setfill('.') << i 
                    << std::setw(15) << std::setfill(' ') << sqrt(i) << std::setw(15) << sqrt(sqrt(i)) << std::endl;
    }
    return 0;
}

//下面為輸出
   N     squre root    fourth root
..10         3.1623         1.7783
..20         4.4721         2.1147
..30         5.4772         2.3403
..40         6.3246         2.5149
..50         7.0711         2.6591
..60         7.7460         2.7832
..70         8.3666         2.8925
..80         8.9443         2.9907
..90         9.4868         3.0801
.100        10.0000         3.1623

cin進行輸入

cin可自動識別輸入的數據類型,也就是說,它讀取從非空白符開始到與目標類型不匹配的第一個字符之間的所有內容.剩下不匹配的內容(如果還有的話)將留在輸入流中等待下一個cin語句讀取.如果輸入與預期不匹配時,那么cin操作的對象將不會被改變并返回狀態0.可用來檢查輸入是否合法.

單字符輸入

  • get(char&)和get() 提供不跳過空白符的單字符輸入功能
  • get(char,int,char)和getline(char,int,char)在默認情況下讀取整行而不是一個單詞.

在有參數和沒參數的情況下,get()方法都讀取下一個輸入字符,即使是不可見字符.get(char&)將輸入的字符賦給其參數并返回istream對像(意味著可拼接,如cin.get(c1).get(c2)),get(void)將輸入的字符轉換為整形再返回.如下是兩種方式讀取到文件末尾的寫法:

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

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

字符串輸入

成員函數getline(),get()都有讀取字符串的版本,他們的特征標都相同:

  • istream& get(char*,int,char);
  • istream& get(char*,int);
  • istream& getline(char*,int,char);
  • istream& getline(char*,int);
  • istream& ignore(int,char);//int表示讀取最大字符數,char表示分界符

第一次參數表示輸入字符串的內存單元地址,第二個參數表示讀取的最大字符數(通常要加1用于存儲字符串結尾字符),第三個參數表示用于分界的字符串,也就是用于指定停止輸入的字符.要是沒有第三個參數則默認用換行符用作分界符.
上面get和getline的功能都是一樣的,只有一點區別,get會將分解符留在輸入流中,而getline則讀取分解符并丟棄掉.
其中ignore(int,char)用于讀取指定數目的字符或者直到分界符為止,并把讀取到的字符串丟棄.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • C/C++輸入輸出流總結 前兩天寫C++實習作業,突然發現I/O是那么的陌生,打了好長時間的文件都沒有打開,今天終...
    LuckTime閱讀 1,752評論 0 6
  • 淺談C++常用輸入輸出 在編寫C++程序的時候,經常因為輸入輸出頭疼,所以在這里做一個小結,記錄一下常用的輸入輸出...
    MinoyJet閱讀 3,777評論 0 6
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,537評論 1 51
  • 收起鋒芒 像只披著羊皮的狼 在人群里張望 在舞臺上猖狂 只為一點兒飽腹食糧 深埋心底的傷 表演可愛模樣 你的演出 ...
    螢火之楓閱讀 153評論 0 1
  • 這篇分享很簡單喲~ 元音字母a e i o u在不同情況下發音也不同,分為長音和短音。 元音字母讀長音的情況: 1...
    阿宅大人冬安閱讀 4,249評論 2 6