C++ 中的 IO 流簡單使用

之前我們提到過,在 C 語言中,使用 scanf,printf 等函數實現輸入和輸出,但是在 C++ 中則是採用了 cin,cout以及流操作符進行輸入和輸出操作。

IO 類

但實際上不管是 cin 還是 cout,兩者都是類對象,主要的類的繼承關係爲:

而在 iostream 中已經事先定義了 cin,cout,cerr,clog 等對象,因此能夠在包含頭文件和聲明命名空間之後直接使用。

上邊各個類的主要作用爲:

iostream istream 從流中讀取
ostream 寫入到流
iostream 從流中讀取,寫入到流
fstream ifstream 從文件中讀取
ofstream 寫入到文件
fstream 從文件中讀取,寫入到文件

IO 流特性

  • 對象不可複製或賦值
  • IO 對象是緩衝的,刷緩衝的時機爲:
    • 程序正常結束,將清空所有緩衝區
    • 緩衝區滿
    • flush 會刷緩衝,endl 在刷緩衝後還會換行
    • 在每次輸出操作執行完成後,可以使用 unitbuf 操作符設置流的內部狀態,清空緩衝區

<</>>

現在可以知道流對象後可以接 <</>> 是函數重載的結果了。

標準輸出

輸出流對象

  • cout:可以輸出基本類型數據,與 printf 相比,不用指定要輸出的數據類型,內部經過重載,因此係統會自動判斷,選擇相應的重載函數。但用戶如果想要輸出自定義的類型時,就需要進行 << 重載
  • cerr:能夠在屏幕上輸出錯誤信息,不能將信息輸出到文件
  • clog:與 cerr 類似,只是不帶有緩衝區

iomanip

C 語言能夠通過格式控制字符來控制輸出的格式,在 C++ 中則是通過流算子來進行格式控制的:

控制符 描述
dec 十進制輸出
hex 十六進制輸出
oct 八進制輸出
setfilll(n) 在給定的輸出域寬度內填充字符n
setprecison(n) 設置小數顯示精度爲n
setw(n) 設置輸出域寬爲n
setiosflags(ios::fixed) 固定的浮點顯示
setiosflags(ios::showpos) 顯示符號
setiosflags(ios::scientific) 指數顯示
setiosflags(ios::left) 左對齊
setiosflags(ios::right) 右對齊
setiosflags(ios::skipws) 忽略前導空白
setiosflags(ios::uppercase) 十六進制大寫輸出
resetiosflags(ios::lowercase) 恢復小寫輸出
setiosflags(ios::showbase)

當按十六進制輸出數據時,前面顯示前導符 0x

當按八進制輸出數據時,前面顯示前導符 0

endl 刷新緩衝區並換行
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    int x = 500;

    cout<<dec<<x<<endl;
    cout<<oct<<x<<endl;
    cout<<hex<<x<<endl;
    cout<<setw(5)<<setfill('*')<<x<<endl;
    cout<<dec<<endl;

    double y = 1.111111111111111;

    cout<<y<<endl;
    cout<<setprecision(2)<<y<<endl;
    cout<<setw(5)<<y<<endl;

    cout<<setiosflags(ios::fixed)<<y<<endl;
    cout<<setw(5)<<setiosflags(ios::left)<<x<<endl;
    cout<<setw(5)<<setiosflags(ios::right)<<x<<endl;
    cout<<dec<<setiosflags(ios::skipws)<<x<<endl;
    cout<<hex<<setiosflags(ios::uppercase)<<x<<endl;
    cout<<hex<<resetiosflags(ios::uppercase)<<x<<endl;
    cout<<hex<<setiosflags(ios::showbase)<<x<<endl;

    return 0;
}

結果爲:

500
764
1f4
**1f4

1.11111
1.1
**1.1
1.11
500**
**500
500
1F4
1f4
0x1f4

成員函數

put

typedef basic_ostream<_CharT, _Traits>		__ostream_type;
__ostream_type& put(char_type __c);

可以得知,put 函數的參數爲 char,返回值爲流引用。

主要作用就是輸出一個字符,類似於 putchar。

#include <iostream>

using namespace std;

int main()
{
    char *p = "hello";
    while (*p)
        cout.put(*p++);

    return 0;
}

結果爲:

hello

標準輸入

cin 是 C++ 中的標準輸入,cin 利用重載的 >> 能夠連續輸入多項內容。和標準輸出一樣,如果需要輸入用戶自定義數據類型,則需要對 >> 進行重載。

#include <iostream>

using namespace std;

int main()
{
    int x;
    double y;
    char z;

    cin>>x>>y>>z;

    cout<<x<<endl;
    cout<<y<<endl;
    cout<<z<<endl;

    return 0;
}

結果爲:

10 10.2 a
10
10.2
a

輸入字符以空白字符作爲分隔符,空白字符包括空格,TAB,ENTER。

成員函數

使用 cin 時,如果字符串中含有空白字符,對於 cin 來說就有點應付不來了。因此成員函數作爲標準輸入的補充內容,可以應付一些比較特殊的情況。

char get()

int_type get();

和 put() 相反,get() 能夠讀入一個字符(包括空白字符),有點類似於 getchar()。

#include <iostream>

using namespace std;

int main()
{
    char c;
    c = cin.get();
    cout<<c<<endl;

    return 0;
}

istream get(char &)

__istream_type& get(__streambuf_type& __sb)
{ return this->get(__sb, this->widen('\n')); }

get() 還能夠有參數,此時讀入一個字符,讀取成功則返回非 0,失敗則返回 0;

#include <iostream>

using namespace std;

int main()
{
    char c;
    cin.get(c);
    cout<<c<<endl;

    return 0;
}

istream &get(char *,int,char)

__istream_type& get(char_type* __s, streamsize __n, char_type __delim);
  • char *:表示字符指針
  • int:表示字符個數
  • char:表示終止字符
  • 函數表示從輸入流中讀取 n-1 個字符,將讀取到的字符賦給字符指針指向的地址
  • 如果在讀取完畢之前提前遇到終止字符,則提前結束讀取;
  • 如果成功則返回非 0,失敗則返回 0;
  • 會清空 char * 指向的空間,未讀到 n-1 個字符或中止符,則會阻塞
  • 不會越過中止符
#include <iostream>

using namespace std;

int main()
{
    char p[100];
    cin.get(p,10,'o');
    cout<<p<<endl;

    return 0;
}

istream &getline(char *,int,char)

__istream_type& getline(char_type* __s, streamsize __n, char_type __delim);

與上一個函數的含義差不多。

  • char *:表示字符指針
  • int:表示字符個數
  • char:表示終止字符
  • 函數表示從輸入流中讀取 n-1 個字符,將讀取到的字符賦給字符指針指向的地址
  • 如果在讀取完畢之前提前遇到終止字符(默認爲 '\n'),則提前結束讀取;
  • 如果成功則返回非 0,失敗則返回 0;
  • 會清空 char * 指向的空間,未讀到 n-1 個字符或中止符,則會阻塞
  • 會越過中止符

該函數與上一個函數的區別就在於對於中止符的處理上,get 在遇到中止符時,會停止當前動作,中止符仍處於流中,再次調用之前需要使用不帶參數的 get() 去除掉該中止符,否則該函數會直接返回,getline 則不會發生這個問題。

#include <iostream>

using namespace std;

int main()
{
    char p[100];
    cin.get(p,10,'o');
    cout<<p<<endl;
    cin.get();
    cin.get(p,10,'o');
    cout<<p<<endl;

    cin.getline(p,10,'o');
    cout<<p<<endl;
    cin.getline(p,10,'o');
    cout<<p<<endl;

    return 0;
}

結果爲:

hellohellohellohellohellohellohello
hell
hell

hell

上邊的結果表示:

  • get 不會越過中止符,因此需要 cin.get() 從當前輸入流中讀走中止符
  • 而 getline 顯然沒有這種限制

ignore

忽略流中的 n 個字符,或者讀取到中止符未知(包含中止符),n 默認爲 1

__istream_type& ignore(streamsize __n, int_type __delim);
__istream_type& ignore(streamsize __n);
__istream_type& ignore();
#include <iostream>

using namespace std;

int main()
{
    char p[100];

    cin.ignore(2);
    cin.getline(p,10,'\n');
    cout<<p<<endl;

    return 0;
}

結果爲:

hello world
llo world

peek

讀取流中的一個字符然後將之放回原位置,指針指向不發生改變。

#include <iostream>

using namespace std;

int main()
{
    char p[100];

    cin.ignore(1);
    cout<<static_cast<char>(cin.peek())<<endl;
    cin.getline(p,6,'\n');
    cout<<p<<endl;

    return 0;
}

結果爲:

hello world
e
ello

putback

插入當前指針位置

#include <iostream>

using namespace std;

int main()
{
    char p[100];

    cin.putback('l');
    cin.getline(p,6,'\n');
    cout<<p<<endl;

    return 0;
}

結果爲:

hello world
lhell
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章