日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

c++进阶---IO类的详细介绍(一)

發(fā)布時(shí)間:2024/4/18 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++进阶---IO类的详细介绍(一) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

IO類
c++為了更好的處理不同的種類的IO的操作,IO庫(kù)中定義了龐大的類庫(kù)來(lái)處理不同種類的IO操作,該類庫(kù)組成如下圖所示:

首先,我們先了解一下這個(gè)龐大的IO庫(kù)各個(gè)類之間的關(guān)系。

ios是最基本的父類,其中istream類和ostream類都繼承了ios類。
iostream類通過(guò)多重繼承繼承了istream類和ostream類。
ifstream、istringstream兩個(gè)類都是繼承了istream類,oftream、ostringstream兩個(gè)類都繼承了ostream類。
OK,另外,我們要知道:

處理標(biāo)準(zhǔn)輸入輸出的類:istream(從流中讀取數(shù)據(jù),即處理輸入)、ostream(向流中寫入數(shù)據(jù),即處理輸出)、iostream(處理輸入和輸出),這些類都被定義在頭文件:iostream中。
處理文件的輸入和輸出的類:ifstream(從文件讀取數(shù)據(jù))、ofstream(向文件寫入數(shù)據(jù))、fstream(讀寫文件),這些類都被定義在頭文件:fstream中
處理string流的類:istringstream(從string中讀取數(shù)據(jù))、ostringstream(向string寫入數(shù)據(jù))、stringstream(讀寫string)。然后,這些類都是定義在頭文件:sstream中。
另外,我們?cè)傺a(bǔ)充一下標(biāo)準(zhǔn)輸入輸出中的一些知識(shí):

cin是STL中定義的一個(gè)istream對(duì)象,它的作用是用于輸入。
cout、cerr、clog是STL中定義的一個(gè)ostream對(duì)象,它們的作用是用于輸出,其中cout是標(biāo)準(zhǔn)輸出,cerr是用于輸出錯(cuò)誤或者警告信息,clog是用于輸出程序的一般性信息。其中cerr不經(jīng)過(guò)緩沖區(qū),直接把錯(cuò)誤信息輸出到顯示器中,clog則先把信息放在緩沖區(qū)中。如果我們輸入一個(gè)endl,那么它將會(huì)把我們輸出緩沖區(qū)的內(nèi)容全部輸出,并且輸出一個(gè)換行。
cin的詳解
程序的每次輸入都會(huì)建立一個(gè)輸入緩沖區(qū)。而我們的cin就是直接從這個(gè)輸入緩沖區(qū)獲取數(shù)據(jù)的,如果我們的緩沖區(qū)中有數(shù)據(jù)殘留(不為空時(shí)),那么cin對(duì)象直接從緩沖區(qū)讀取數(shù)據(jù)而不是請(qǐng)求輸入。另外,之前我們已經(jīng)說(shuō)過(guò)了cin是istream定義的一個(gè)對(duì)象,所以我們每次使用cin進(jìn)行請(qǐng)求輸入的時(shí)候,都是在調(diào)用istream這個(gè)對(duì)象的方法,其中istream這個(gè)對(duì)象處理輸入的方法三種:cin>> 、cin.get() 、cin.getline().另外,cin是可以連續(xù)從緩沖區(qū)中讀取想要的數(shù)據(jù)的,它是以(tab 、space、enter)中的一種作為分隔符,

cin>>方法的介紹
注意事項(xiàng):
(1)cin>>,其實(shí)是調(diào)用類的:istream & operator >>方法,它很多種重載的版本,分別用于處理字符、浮點(diǎn)數(shù)、整型等數(shù)據(jù)類型的輸入。
(2)cin>>,這個(gè)方法遇到了分割符(tab 、space、enter)時(shí),就返回結(jié)束該次cin>>方法的調(diào)用。然后,如果我們調(diào)用cin>>方法時(shí),從緩沖區(qū)讀取數(shù)據(jù),如果開(kāi)頭的數(shù)據(jù)是分隔符,那么直接把分割符忽略并且清除,直至第一個(gè)字符不是分隔符時(shí)才開(kāi)始輸入。
示例展示:

#include<iostream>
#include<string>
using namespace std;
int main()
{
? ? int num;
? ? string s;
? ? cin >> num >> s;
? ? cout << num << " " << s << endl;

? ? getline(cin,s);
? ? cout << "string:" << s << endl;
? ? cout << endl;
? ? cout << "test" << endl;
? ? cout << endl;
? ? return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
輸入:
[回車][回車][回車]12 abcd[回車]

輸出:?
ps:首先了getline函數(shù)是不會(huì)忽略開(kāi)頭的分割符的,我們開(kāi)始保存到緩沖區(qū)的三個(gè)回車都被cin>>方法忽略了,而最后一個(gè)回車也在緩沖區(qū)中,但是沒(méi)有被忽略,而是被geiline函數(shù)讀了進(jìn)來(lái),所以在輸出test之前會(huì)有兩個(gè)換行。

cin.get()方法介紹
注意事項(xiàng):
(1)cin.get()它有四種比較常見(jiàn)的重載格式:
int cin.get(); ? ?//不帶參數(shù)時(shí),返回值為整型,但遇到了文件的結(jié)束,返回EOF,其實(shí)就是:-1
istream & cin.get(char & s) //返回值為輸入流。
istream & cin.get(char * s,streamsize n) //用于輸入一個(gè)字符串,但是它只接受參數(shù)時(shí)c語(yǔ)言風(fēng)格字符串風(fēng)格的參數(shù),即是不接受string類的參數(shù),而且它默認(rèn)是以換行作為結(jié)束符。
istream & cin.get(char * s,streamsize n,char end) //用于輸入一個(gè)字符串,同樣參數(shù)必須是c風(fēng)格的,當(dāng)時(shí)它是以:字符end,作為結(jié)束符。
1
2
3
4
5
(2)上面的streamsize在頭文件iostream中的定義為long long型的數(shù)據(jù)類型的別名。所有版本的cin.get()方法是不會(huì)忽略開(kāi)頭的分隔符符號(hào)的,而且它和cin>>一樣,遇到分隔符(tab、space 、enter)時(shí),就結(jié)束該次方法的調(diào)用。最后的那個(gè)分隔符還是保存在緩沖區(qū)中。

示例展示:

#include<iostream>
using namespace std;
int main()
{
? ? char s;

? ? char s1;
? ? s1 = cin.get();
? ? cin.get(s);
? ? cout << (int)s1 << " " << (int)s << endl;?

? ? char str[5] = {NULL};
? ? char end;
? ? cin.get(str,5);
? ? cin.get(end);
? ? cout << str << " " << (int)end << endl;
? ? cout << endl;
? ? return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
輸入:
[回車][回車]test[回車]

輸出:


ok,我們從結(jié)果可以看出,我們開(kāi)始輸入的兩個(gè)回車都被作為s1和s的初始值了,而我們字符串的最后一個(gè)回車也被end作為初始值了,從而可以看出cin.get()是不會(huì)忽略緩沖區(qū)中的分隔符的。

cin.getline()方法的介紹
注意事項(xiàng):
(1)cin.getline()方法重要的幾個(gè)重載版本
//這里我cin.get后面的兩個(gè)方法一樣,用于輸入字符串。
//cin.getline不會(huì)將最后一個(gè)輸入的結(jié)束符或者換行符殘留在輸入緩沖區(qū)中,
//而是一起輸出到顯示器中。默認(rèn)遇到‘\n’結(jié)束輸入。
istream & cin.getline(char *s ,streamsize n)?
//這個(gè)方法就是結(jié)束方式不同,它是遇到了字符:end就結(jié)束輸入。然后,輸出長(zhǎng)度為n-1范圍內(nèi),end之前的所有字符。

istream & cin.getline(char * s,streamsize n,char end)?
1
2
3
4
5
6
7
8
代碼示例:

#include<iostream>
#include<string>
using namespace std;
int main()
{
? ? char s[5];
? ? char t;
? ? cin.getline(s, 5);
? ? cout << s << endl;;
? ? cin >> t;
? ? cout << t << endl;
? ? cout << endl;
? ? return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
輸入:
new[回車]f
輸出:

ok,從輸出的結(jié)果,我們可以發(fā)現(xiàn),cin.getline是把我們輸入緩沖區(qū)的那個(gè)回車一并輸出來(lái)了。

補(bǔ)充:getline函數(shù)的介紹(用于輸入一行時(shí)使用,接受空格的輸入)
(1):C++中定義了一個(gè)在std名字空間的全局函數(shù)getline,因?yàn)檫@個(gè)getline函數(shù)的參數(shù)使用了string字符串,所以聲明在了string頭文件中了。
getline利用cin可以從標(biāo)準(zhǔn)輸入設(shè)備鍵盤讀取一行,當(dāng)遇到如下三種情況會(huì)結(jié)束讀操作:1)到文件結(jié)束,2)遇到函數(shù)的定界符,3)輸入達(dá)到最大限度。
函數(shù)原型有兩個(gè)重載形式:

istream& getline ( istream& is, string& str);//默認(rèn)以換行符結(jié)束

istream& getline ( istream& is, string& str, char end);//以end字符結(jié)束
1
2
3
(2)注意,getline遇到結(jié)束符時(shí),會(huì)將結(jié)束符一并讀入指定的string中,再將結(jié)束符替換為空字符。因此,進(jìn)行從鍵盤讀取一行字符時(shí),建議使用getline,較為安全。但是,最好還是要進(jìn)行標(biāo)準(zhǔn)輸入的安全檢查,提高程序容錯(cuò)能力。另外,cin.getline()類似,但是cin.getline()屬于istream流,而getline()屬于string流,是不一樣的兩個(gè)函數(shù)。

代碼示例:

#include<iostream>
#include<string>
using namespace std;
int main()
{
? ? string str;
? ? getline(cin, str);
? ? cout << str;
? ? cout << endl;
? ? return 0;
}
1
2
3
4
5
6
7
8
9
10
11
輸入:
i am a student;
輸出:


gets_s 函數(shù)的介紹(一般不要用它好了,c中定義的語(yǔ)法),原來(lái)是gets,但是在新的vs2015中已經(jīng)沒(méi)有g(shù)ets了。只有g(shù)ets_s
gets是C中的庫(kù)函數(shù),在< stdio.h>申明,從標(biāo)準(zhǔn)輸入設(shè)備讀字符串,可以無(wú)限讀取,不會(huì)判斷上限,以回車結(jié)束或者EOF時(shí)停止讀取,所以程序員應(yīng)該確保buffer的空間足夠大,以便在執(zhí)行讀操作時(shí)不發(fā)生溢出。
函數(shù)原型:char *gets_s( char *buffer );

代碼示例:

#include<iostream>
using namespace std;
int main()
{
? ? char array[20] = { NULL };
? ? gets_s(array);
? ? cout << array << endl;
? ? return 0;
}
1
2
3
4
5
6
7
8
9
輸入:
new find
輸出:


重點(diǎn)內(nèi)容補(bǔ)充:IO類的對(duì)象都是不可以拷貝的,所以如果我們需要使用IO類的對(duì)象作為函數(shù)的參數(shù)的時(shí)候或者返回值的時(shí)候,我們都要使用引用類型

條件狀態(tài)
因?yàn)槲覀冊(cè)谑褂肐O類的時(shí)候,總會(huì)出現(xiàn)一些錯(cuò)誤,于是每個(gè)IO類都定義了一個(gè)iostate這個(gè)數(shù)據(jù)類型表示當(dāng)前某個(gè)操作所處的狀態(tài)。其中IO庫(kù)定義了4個(gè)iostate類型的constexpr的值,它們分別是:

strm::badbit :首先,我們要說(shuō)明strm代表的是IO類中的一種,例如istream、ostream、fstream等,babit表示系統(tǒng)級(jí)的錯(cuò)誤,如果IO發(fā)生了不可修復(fù)的錯(cuò)誤,badbit將被置位,而且流將無(wú)法再使用。

strm::failbit:這個(gè)會(huì)在流發(fā)生可修復(fù)的錯(cuò)誤時(shí),failbit將會(huì)被置位,例如:當(dāng)我們本來(lái)是要求輸入一個(gè)數(shù)值的卻輸入了一個(gè)字符等錯(cuò)誤,這種問(wèn)題可以被修正的,流還可以繼續(xù)被使用。

strm::eofbit:當(dāng)流達(dá)到了文件的結(jié)束的位置,eofbit和failbit這兩個(gè)狀態(tài)都會(huì)被置位。

strm::goodbit:當(dāng)goodbit的值為1時(shí),表示流未發(fā)生錯(cuò)誤。

最后就是,只要badbit、eofbit、failbit任意一個(gè)狀態(tài)被置位,那么一切以流狀態(tài)為條件的語(yǔ)句都是返回false。例如:while(cin>>word),這條語(yǔ)句,只要上述三個(gè)中,有一個(gè)被置位,循環(huán)就結(jié)束。

IO庫(kù)中還定義了一組函數(shù),用于查詢當(dāng)前某種狀態(tài)的值。具體函數(shù)如下:其中s為一個(gè)流的對(duì)象。

s.eof() // 若流s的eofbit置位,則返回true
s.fail() // 若流s的failbit或badbit置位,則返回true
s.bad() // 若流s的badbit被置位,則返回true
s.good() // 若流s處于有效狀態(tài),則返回true
1
2
3
4
在實(shí)際我們?cè)谘h(huán)中判斷流的狀態(tài)是否有效時(shí),都直接使用流對(duì)象本身,比如:while(cin>>variable){cout<

#include<iostream>
using namespace std;
int main()
{
? ? int t;
? ? while (cin>>t)
? ? {
? ? ? ? cout << "cin.good的值:"<<cin.good() << endl;
? ? ? ? cout << "cin.eof的值:" << cin.eof() << endl;
? ? ? ? cout << "cin.fail的值:" << cin.fail() << endl;
? ? ? ? cout << "cin.bad的值:" << cin.bad() << endl;
? ? }
? ? cout << "結(jié)束后" << endl;
? ? cout << "cin.good的值:" << cin.good() << endl;
? ? cout << "cin.eof的值:" << cin.eof() << endl;
? ? cout << "cin.fail的值:" << cin.fail() << endl;
? ? cout << "cin.bad的值:" << cin.bad() << endl;

? ? system("pause");
? ? return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
輸入:1[空格]2[空格]d[回車]
輸出:


IO類庫(kù)還提供了3個(gè)函數(shù)來(lái)管理和設(shè)置流的狀態(tài):

s.clear(); // 將流s中所有條件狀態(tài)復(fù)位,將流的狀態(tài)設(shè)置為有效,調(diào)用good會(huì)返回true
s.clear(flags); // 根據(jù)給定的flags標(biāo)志位,將流s中對(duì)應(yīng)的條件狀態(tài)復(fù)位,flags的類型為iostate
s.setstate(flags); // 根據(jù)給定的flags標(biāo)志位,將流s中對(duì)應(yīng)的條件狀態(tài)置位。,flags的類型為iostate
s.rdstate(); // 返回一個(gè)iostate類型的值,對(duì)應(yīng)流當(dāng)前的狀態(tài)。
1
2
3
4
注釋:Windows下標(biāo)準(zhǔn)輸入輸入文件結(jié)束符為Ctrl+z,Linux為Ctrl+d。

最后就是,我們來(lái)完成一下《c++ primer 第五版》的281那個(gè)練習(xí)題,代碼如下:

#include<iostream>
#include<string>
using namespace std;

istream & test(istream & s)
{
? ? string str;

? ? while ((s >> str).eof() == false)
? ? {
? ? ? ? cout << str << " " << endl;
? ? }
? ? cout << "結(jié)束" << endl;
? ? s.clear();
? ? return s;
}

int main()
{
? ? //Windows下標(biāo)準(zhǔn)輸入輸入文件結(jié)束符為Ctrl+z,Linux為Ctrl+d。
? ? test(cin);
? ? system("pause");
? ? return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
測(cè)試結(jié)果:


緩沖區(qū)詳解
(1)輸入緩沖區(qū)

觀察如下代碼:

#include<iostream>
using namespace std;


int main()
{
? ? char ch;
? ? while (cin >> ch)
? ? {
? ? ? ? cout << ch;
? ? }

? ? system("pause");
? ? return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我們預(yù)想的是,我們輸入一個(gè)字符就顯示一個(gè)字符,但是實(shí)際上情況是如下圖:


其實(shí),輸入字符立即回顯是非緩沖或直接輸入的一個(gè)形式,它表示你所鍵入的字符對(duì)正在等待的程序立即變?yōu)榭捎?。相?#xff0c;延遲回顯是緩沖輸入的例子,這種情況下你所鍵入的字符塊被收集并存儲(chǔ)在一個(gè)被稱為緩沖區(qū)的臨時(shí)存儲(chǔ)區(qū)域中。按下回車鍵可使你輸入的字符段對(duì)程序起作用。

緩沖輸入一般常用在文本程序內(nèi),當(dāng)你輸入有錯(cuò)誤時(shí),就可以使用你的鍵盤更正修正錯(cuò)誤。當(dāng)最終按下回車鍵時(shí),你就可以發(fā)送正確的輸入。

而在一些交互性的游戲里需要非緩沖輸入,如:游戲里你按下一個(gè)鍵時(shí)就要執(zhí)行某個(gè)命令。

輸入緩沖分類:

完全緩沖:緩沖區(qū)被充滿時(shí)被清空(內(nèi)容發(fā)送到其目的地)。這種類型的緩沖通常出現(xiàn)在文件輸入中。

行緩沖:遇到一個(gè)換行字符時(shí)被清空緩沖區(qū)。鍵盤的輸入是標(biāo)準(zhǔn)的行緩沖,因此按下回車鍵將清空緩沖區(qū)

(2)輸出緩沖區(qū)

每個(gè)輸出流都會(huì)管理一個(gè)緩沖區(qū),用了保存程序讀寫的數(shù)據(jù),這個(gè)和輸入緩沖區(qū)是一個(gè)道理的,但是輸出不一樣,我們是希望在程序結(jié)束是,輸出緩沖區(qū)中的內(nèi)容都要被輸出去,所以會(huì)有緩沖區(qū)刷新,在下面這幾種情況會(huì)引起緩沖區(qū)的刷新(注意:如要程序異常終止,輸出緩沖區(qū)是不會(huì)被刷新的。當(dāng)一個(gè)程序崩潰后,它所輸出的數(shù)據(jù)很可能停留在輸出緩沖區(qū)中等待打印。所以最好在每個(gè)輸出后加一個(gè)緩沖區(qū)刷新的操作):

程序正常結(jié)束,作為main函數(shù)的return操作的一部分,緩沖刷新被執(zhí)行。

緩沖區(qū)滿時(shí),需要刷新緩沖,而后新的數(shù)據(jù)才能繼續(xù)寫入緩沖區(qū)。

我們可以使用操縱符endl來(lái)顯式刷新緩沖區(qū)。

在每個(gè)輸出之后,我們可以用操縱符unitbuf設(shè)置流的內(nèi)部狀態(tài),來(lái)清空緩沖區(qū)。默認(rèn)情況下,對(duì)cerr是設(shè)置unitbuf的,因此寫到cerr的內(nèi)容都是立即刷新的。

一個(gè)輸出流被關(guān)聯(lián)到另一個(gè)流。在這種情況下,當(dāng)讀寫被關(guān)聯(lián)的流時(shí),關(guān)聯(lián)到的流的緩沖區(qū)會(huì)被刷新,cin和cerr都關(guān)聯(lián)到cout。因此讀cin或?qū)慶err會(huì)導(dǎo)致cout的緩沖區(qū)被刷新(cin立即回顯的一個(gè)原因)。

IO庫(kù)中除了endl可以刷新緩沖區(qū)外,ends和flush也會(huì)刷新緩沖區(qū)。只是它們會(huì)有一點(diǎn)差別:

cout << "hi!" << endl; // 輸出 hi 和一個(gè)換行符,然后刷新緩沖區(qū)?
cout << "hi!" << flush; // 輸出hi,然后刷新緩沖區(qū),不附加任何額外字符?
cout << "hi!" << ends; // 輸出hi和一個(gè)空字符。然后刷新緩沖區(qū)
1
2
3
unitbuf操作符,如果我們希望每次輸出操作后都要刷新緩沖區(qū),那么就可以使用:unitbuf,它就是告訴系統(tǒng),以后每次進(jìn)行輸出操作后都要指向flush操作,我們之前提到的cerr就是設(shè)置了unitbuf的

cout << unitbuf; // 所有輸出操作后都立即刷新緩沖區(qū)?
// 任何輸出都立即刷新,無(wú)緩沖?
cout << nounitbuf; // 回到正常的緩沖方式
1
2
3
4
點(diǎn)贊 4
————————————————
版權(quán)聲明:本文為CSDN博主「Ouyang_Lianjun」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_35644234/article/details/56679127

總結(jié)

以上是生活随笔為你收集整理的c++进阶---IO类的详细介绍(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。