C++學習-入門到精通【11】輸入/輸出流的深入剖析

C++學習-入門到精通【11】輸入/輸出流的深入剖析


目錄

  • C++學習-入門到精通【11】輸入/輸出流的深入剖析
    • 一、流
      • 1.傳統流和標準流
      • 2.iostream庫的頭文件
      • 3.輸入/輸出流的類的對象
    • 二、輸出流
      • 1.char* 變量的輸出
      • 2.使用成員函數put進行字符輸出
    • 三、輸入流
      • 1.get和getline成員函數
      • 2.istream的成員函數peek、putback和ignore
      • 3.類型安全
    • 四、使用read、write和gcount的非格式化的I/O
    • 五、流操縱符簡介
      • 1.整數流的基數:dec、oct、hex和setbase
      • 2.浮點精度
      • 3.位寬(width和setw)
      • 4.用戶自定義輸入流操縱符
    • 六、流的格式狀態和流操縱符
      • 1.尾數零和小數點(showpoint)
      • 2.對齊(left、right和internal)
      • 3.內容填充(fill和setfill)
      • 4.整數流的基數
      • 5.浮點數、科學計數法和定點小數記數法(scientific、fixed)
      • 6.大寫/小寫控制(uppercase)
      • 7.指定布爾類型(boolalpha)
      • 8.通過成員函數flags設置和重置格式狀態
    • 七、流的錯誤狀態


一、流

C++的I/O是以一連串的字節流的方式進行的。在輸入操作中,字節從設備(例如,鍵盤、磁盤驅動器、網絡連接等)流向內存。在輸出操作中,字節從內存流向設備(例如,顯示屏、打印機、磁盤驅動器、網絡連接等)。入:表示進入內存;出:表示離開內存。以內存為參照物。

這里的流是一個抽象的概念,表示一個連續的數據序列。對于上面的不同設備而言,它們處理的數據格式其實并不相同,所以我們使用一個流的抽象概念將數據的生產者和消費者解耦(生產者只需將生成的數據給到流,之后輸出到各種設備的不同操作由流來決定;反之亦然。)這就使得程序只需關注數據本身,不需要關注到數據如何流動到不同設備之中。

應用程序通過字節傳達信息。字節可以組成字符、原始數據、圖形圖像、數字語音、數字視頻或者任何應用程序所需要的其他信息。系統I/O結構應該能持續可靠地將字節從設備傳輸到內存,反之亦然。這種傳輸在設備中往往包含一些機械運動,例如,磁盤的旋轉,或鍵盤的敲擊。數據傳輸所花費的時間遠遠大于處理器內部處理數據所需要的時間。所以I/O操作需要仔細計劃和協調,以保證最優的性能。

C++中同時提供低層次的高層次的I/O功能。
低層次的I/O功能(也就是非格式化的I/O)指定字節應從設備傳輸到內存還是從內存傳輸到設備。這種傳輸通過針對單個字節,并提供速度快、容量大的傳輸。但是對于程序員來說不方便。
程序員通常更喜歡高層次的I/O(也就是格式化的I/O)。因為在這種輸出方式中字節被組成了有意義的單元,例如整數、浮點數、字符、字符串或者用戶自定義類型。除了大容量文件處理之外,這種面向類型的方法能夠滿足絕大多數的I/O處理。

1.傳統流和標準流

C++的傳統流庫(<stdio.h>中的函數)允許輸入/輸出char類型的字符。一個char只占據一個字節的大小,它只能表示一個字符的有限集(例如,ASCII字符集)。然而,許多語言使用的字母表包含更多的符號,這是單字節的char無法表示的。

C++包含標準流庫(,之類的庫),可以描述這些新的字符。

2.iostream庫的頭文件

絕大多數C++程序都包含了<iostream>頭文件,該頭文件中聲明了所有I/O操作所需的基礎服務。其中定義了cin、cout、cerr和clog對象,分別對應于標準輸入流、標準輸出流、無緩沖的標準錯誤流和有緩沖的標準錯誤流。同時還提供了非格式化和格式化的I/O服務。

<iomanip>頭文件中聲明了參數化流操縱符(例如,之前我們使用過的setw和setprecision)用于向格式化I/O提供有用的服務。

<fstream>頭文件中聲明了文件處理服務。

3.輸入/輸出流的類的對象

iostream庫提供了許多模板來處理一般的I/O操作。例如,類模板basic_istream支持輸入流操作,類模板basic_ostream支持輸出流操作,類模板basic_iostream同時支持輸入流和輸出流操作。


I/O流模板層次和運算符重載

模板basic_istream和basic_ostream派生自同一個基模板basic_ios。模板basic_iostream則從模板basic_istream和basic_ostream多重繼承而來。下面是它們的UML類圖。

在這里插入圖片描述

運算符重載為輸入和輸出操作提供了更加方便的符號。左移運算符<<被重載用于實現流的輸出,被稱為流插入運算符,右移運算符>>被重載用于實現流的輸入,被稱為流提取運算符。這些運算符通常與標準流對象cin、cout、cerr和clog,以及用戶自定義的流對象一起使用。


標準流對象cin、cout、cerr和clog

預定義對象cin是一個istream類的實例,并且被綁定到標準輸入設備(通常是鍵盤)。在下面的語句中,流提取運算符>>用于使一個整形變量grade的值從cin輸入到內存。
cin >> grade;
注意,由編譯器確定grade的數據類型,并且選擇合適的流提取運算符重載。假設grade已經被正確的聲明,流提取運算符不需要附加任何類型信息(附加類型信息,就像C語言的I/O方式一樣,在函數中顯式的指定輸入數據的類型)。標準庫中重載的>>運算符可以用來輸入內置類型、字符串和指針的值。

預定義對象cout是一個ostream類的實例,并且被綁定到標準輸出設備(通常是顯示器)。在下面的語句中,流插入運算符<<用于將變量grade的值從內存中輸出到標準輸出設備:
cout << grade;
注意,這里也是由編譯器確定grade的數據類型,并且選擇合適的流插入運算符,因此流插入運算符也同樣不需要附加類型信息。

預定義對象cerrclog都是ostream類的實例,且都被綁定到標準錯誤設備。對象cerr的輸出是無緩沖的。每個針對cerr的流插入的輸出必須立刻顯示,這對于迅速提示用戶發生錯誤非常合適。而對象clog是輸出是有緩沖的,每個針對clog的流插入的輸出先保存到緩沖區中,直到緩沖區被填滿或是被清空才會輸出。


文件處理模板

C++文件處理乃至類模板basic_ifstreambasic_ofstreambasic_fstream。模板basic_ifstream繼承自basic_istream,basic_ofstream繼承自basic_ostream,而basic_fstream則繼承自basic_iostream。它們的UML類圖如下:

在這里插入圖片描述

二、輸出流

ostream提供了格式化的和非格式化的輸出功能。輸出功能包括使用流插入運算符<<執行標準數據類型的輸出;通過成員函數put進行字符輸出;通過成員函數write進行非格式化的輸出;十進制、八進制、十六進制格式的整數輸出;具有不同精確度的浮點數的輸出,或是具有強制小數點的浮點數的輸出;用指定符號填充數據域的輸出;以及使用科學計數法和十六進制符號表示的大寫字母的輸出。

1.char* 變量的輸出

C++能自動判定數據類型,這是它相對于C的一種改進。但是,這一特性有時候會產生一些問題。比如,現在我們要打印一個字符串的char*的值(該字符串首字符的地址)。然而,<<運算符已被重載用于打印將char*數據類型作為以空字符結尾的字符串。解決的辦法就是將char*強制轉化為void*類型(如果程序員想輸出一個地址,那么就都應該對指針變量進行這樣的轉換)。

下面就是分別以字符串形式和地址形式輸出char*的值的例子。

#include <iostream>
using namespace std;int main()
{const char* const word = "hehe";cout << "Value of word is " << word<< "\nValue of static_cast<const void*>(word) is " << static_cast<const void*>(word) << endl;
}

運行結果:

在這里插入圖片描述

2.使用成員函數put進行字符輸出

可以使用成員函數put輸出字符,例如,語句:
cout.put('A');
就可以顯示單個字符A。put也可以級聯使用(該成員函數返回的也是一個ostream對象的引用)。例如,
cout.put('A').put('B');

三、輸入流

格式化的和非格式化的輸入功能是由istream來提供的。流提取運算符通常跳過輸入流中的空白字符(例如,空格、制表符和換行符),我們也可以改變它的這種行為。

在每個輸入操作之后,流提取運算符給接收到所提取的信息的流對象返回一個引用。如果引用被用作判斷條件(例如,while(cin >> grade)),那么將隱式調用流重載的void*強制轉換運算符函數,根據最后輸入操作的成功與否,將引用轉化為非空指針或是空指針值。 非空指針值轉化為bool值true,表示操作成功;空指針值則轉化成bool值false,表示操作失敗。

當試圖超過流的末尾進行讀取操作時,流重載的void*強制轉化運算符返回一個空指針,表示已經讀到文件的末尾。

每個流對象都包含一組狀態位來控制流的狀態(例如,格式化、設置錯誤狀態等),流重載的void*強制類型轉換運算符使用這些狀態位來決定是返回非空值還是空值。當輸入錯誤的數據類型時,流提取的failbit狀態位被設置;當操作失敗時,流的badbit位被設置。


1.get和getline成員函數

沒有實參的成員函數get從指定流中輸入一個字符(包括空白字符及其他非圖形字符,比如表示文件尾的鍵序列等),并將這個值作為函數調用的返回值返回。這個版本的get函數在遇到流中的文件尾時返回EOF值。


使用成員函數eof、get和put

在這里插入圖片描述
下面代碼展示了成員函數eof、get和put的使用方法。

#include <iostream>
using namespace std;int main()
{int character;cout << "Before input, cin.eof() is " << cin.eof() << endl<< "Enter a sentence followed by end-of-file:" << endl;while ((character = cin.get()) != EOF){cout.put(character);}cout << "\nEOF in this system is: " << character << endl;cout << "After input of EOF, cin.eof() is " << cin.eof() << endl;
}

注意Windows系統中的文件結束符是通過組合鍵ctrl + z,UNIX系統中組合鍵ctrl + d

運行結果:

在這里插入圖片描述
注意,只有當程序試圖越過流中的最后一個字符進行讀操作時,eof函數才返回true。也就是只有當文件指針指向結束符時,還要再將進行讀取操作,此時eof函數才會返回true。

在這里插入圖片描述

比較cin和cin.get

下面程序對使用流提取cin進行輸入(讀取字符直到遇到空白字符)和cin.get進行輸入的不同之處。注意下面代碼中使用get并沒有指定分隔符,所以它使用默認的分隔字符(\n)。

#include <iostream>
using namespace std;int main()
{const int SIZE = 80;char buffer1[SIZE];char buffer2[SIZE];cout << "Enter a sentence: " << endl;cin >> buffer1;cout << "\nThe string read with cin was:" << endl<< buffer1 << endl << endl;cin.get(buffer2, SIZE);cout << "The string read with cin.get was:" << endl<< buffer2 << endl << endl;
}

運行結果:

在這里插入圖片描述
可以看到cin.get會遇到\n之前的,小于讀取字符數的所有字符。而使用cin進行讀取則只會讀取到第一次遇到空白字符之前的字符。

成員函數getline

在這里插入圖片描述

#include <iostream>
#include <string>
using namespace std;int main()
{string str1;string str2;cout << "Enter a sentence: " << endl;getline(cin, str1, ' ');cout << "\nThe string read with getline(cin, str1, ' ') was:" << endl<< str1 << endl << endl;getline(cin, str2);cout << "The string read with get(cin, str2) was:" << endl<< str2 << endl << endl;
}

運行結果:

在這里插入圖片描述

可以看到使用getline獲取的第二個string對象中,首字符并不是空格(被丟棄了)。

2.istream的成員函數peek、putback和ignore

在這里插入圖片描述

在這里插入圖片描述
putback這個成員函數對于掃描輸入流,在其中搜索以特定字符開頭的字段的應用程序很有用。

例如,此時我們要輸出一個以字母’a’開頭的單詞,所以我們需要從流讀取一個單詞的首字符判斷是否符合要求,在讀取到一個單詞的首字符為’a’時,我們要將這個單詞保存到一個變量中,但是因為我們已經從流中讀取了它的第一個字符,我們現在需要將這個字符’a’放回到流的最前面,使得我們可以從流中再次讀取到這個完整的單詞。

在這里插入圖片描述

該函數也可以實現像上面的putback函數一樣的預讀操作。只是它壓根沒有把字符提取出來,所以也就不需要放回。

3.類型安全

C++提供類型安全的I/O。重載<<>>運算符可接收各種指定類型的數據項,如果遇到意料之外的數據類型,各種相應的錯誤位就會被設置,用戶可以通過檢測錯誤位來判斷I/O操作是否成功。如果沒有為用戶自定義類型重載運算符<<和>>,并且試圖輸入或輸出一個該用戶自定義類型的對象的內容,那么編譯器就會報錯。

四、使用read、write和gcount的非格式化的I/O

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

下面給出一個使用read、write和gcount的例子。

#include <iostream>
using namespace std;#define SIZE 80int main()
{char buffer[SIZE];cout << "Enter a sentence:" << endl;cin.read(buffer, 20); // 從輸入流提取20個字符存入buffer中cout << "The sentence entered was: " << endl;cout.write(buffer, cin.gcount()); // 之前提取了多少個字符,就輸出多個字符cout << endl;
}

運行結果:

在這里插入圖片描述

五、流操縱符簡介

C++提供多種流操縱符來完成格式化的任務。流操縱符的功能包括設置域的寬度、設置精確度、設置和取消格式狀態、設置域的填充字符、刷新流、向輸出流添加新行(并刷新流)、在輸出流中添加一個新字符、跳過輸入流中的空白,等等。

1.整數流的基數:dec、oct、hex和setbase

為了能夠更改流中整數的基數(默認的基數是10,也就是十進制),使之不局限于默認的基數,可以插入hex操縱符基數設置為十六進制,或者插入oct操縱符將基數設置為八進制。插入dec操縱符將整型流的基數重新設置為十進制。

當然除了使用上面提到的流操縱符,還可以使用setbase這個流操縱符來設置基數,該操縱符通過一個整數參數10、8、或16將基數分別設為十進制、八進制或十六進制。由于setbase有一個參數,所以也稱為參數化流操縱符。而要使用任何參數化的操縱符就必須包含<iomanip>這個頭文件。流的基數值只有被顯式更改才會發生變化,所以上面提到這些流操縱符的設置都是“黏性”的。

下面給出這幾個流操縱符的使用示例:

#include <iostream>
#include <iomanip>
using namespace std;int main()
{int number;cout << "Enter a decimal number: ";cin >> number;cout << number << " in hexadecimal is " << hex << number << endl;cout << dec << number << " in octal is " << oct << number << endl;cout << setbase(10) << number << " in setbase(7) is " << setbase(7) << number << endl<< "in setbase(10) is " << setbase(10) << number << endl;
}

運行結果:

在這里插入圖片描述

從結果中可以看出setbase流操縱符只能設置為10、8或16這三種基數。

2.浮點精度

可以使用流操縱符setprecisionios_base的成員函數precision來控制浮點數的精度(也就是小數點右邊的位數)。這兩種操作的設置都是黏性的。調用無參數的成員函數precision將返回當前的精度設置。

下面給出一個使用示例:

#include <iostream>
#include <iomanip>
using namespace std;int main()
{double d = 3.14159265359;cout << "The default precision is " << cout.precision() << "\n\n";cout << "With default precision d is " << d << "\n";cout.precision(8);cout << "With high precision d is " << d << "\n\n";cout << "Current precision is " << cout.precision() << "\n\n";cout << setprecision(6) << "With setprecision(6) d is " << d << "\n\n";cout << fixed;cout << "\nAfter setting fixed:\n\n";cout << "With cout.precision(6) d is ";cout.precision(6);cout << d << "\n\n";cout << "With setprecision(8) d is " << setprecision(8)<< d << "\n\n";
}

運行結果:

在這里插入圖片描述

從結果中看,如果沒有使用流操縱符fixed,成員函數percision和參數化流操縱符setprecision設置的整個浮點數的有效數位;而使用fixed之后,它指定的就是小數點后面的有效位數。

3.位寬(width和setw)

成員函數width(基類是ios_basic)可以設置域寬(也就是輸出值所占的字符位數或是可輸入的最大字符數)并且返回原先的位寬。

在這里插入圖片描述

如果輸出值的寬度比域寬小,則插入填充字符進行填充。寬度大于指定寬度的值不會被截短,會將整個值都打印出來。

提示
寬度設置只適用于下一次輸入或輸出(非黏性),之后的寬度被隱式地設置為0(默認設置)。

使用示例:

#include <iostream>
using namespace std;int main()
{int widthValue = 3;char sentence[10];cout << "Enter a sentence:" << endl;cin.width(5);  // 最多輸入5個字符while (cin >> sentence){cout.width(widthValue++);cout << sentence << endl;cin.width(5);}
}

運行結果:

在這里插入圖片描述

注意,使用cin讀取字符時,會在遇到空白字符時停下,并跳過空白字符,下一次讀取直接從下一個非空白字符開始讀取。
使用width成員函數,會讀取(參數 - 1)個字符,因為需要在每次讀取的字符串后面添加一個\0

所以才會出現上面的輸出。

4.用戶自定義輸入流操縱符

程序員可以創建自己的流操縱符。下面的代碼中展示了創建和使用新的無參數操縱符bellcarriageReturntabendLine。對于輸出流操縱符來說,它們的返回類型都必須是ostream&類型的。

#include <iostream>
using namespace std;// 輸出一個\a
ostream& bell(ostream& output)
{return output << '\a';
}// 輸出一個 \r
ostream& carriageReturn(ostream& output)
{return output << '\r';
}// 輸出一個 \t
ostream& tab(ostream& output)
{return output << '\t';
}// 輸出一個 endl
ostream& endLine(ostream& output)
{return output << '\n' << flush;
}int main()
{cout << "Testing the tab manipulator:" << endLine<< 'a' << tab << 'b' << tab << 'c' << endLine;cout << "Testing the carriageReturn and bell manipulator:" << endLine<< ".....................";cout << bell;cout << carriageReturn << "---------" << endLine;
}

運行結果:

在這里插入圖片描述

六、流的格式狀態和流操縱符

在I/O流操作中,可以使用多種流操縱符來指定各種格式。流操縱符可以控制輸出格式。

下表中列出了類ios_base中可能會使用到的流操縱符。

流操縱符描述
skipws跳過輸出流的空白字符。使用流操縱符noskipws來重置設置
left域的輸出左對齊。必要時在右邊填充字符
right域的輸出右對齊。必要時在左邊填充字符
internal表示域中的數字的符號左對齊,同時域的數字的數值部分右對齊(中間使用填充字符填充)
boolalpha指定bool類型的值以true或false的形式顯示。noboolalpha指定bool類型的值以1或0的形式顯示
dec整數以十進制數顯示
oct整數以八進制數顯示
hex整數以十六進制數顯示
showbase指明在數字的前面顯示該數的基數(以0開頭表示八進制,0x表示十六進制)。使用流操縱符noshowbase可以取消數字前的基數顯示
showpoint指明浮點數必須顯示小數點。通常使用fixed流操縱符來確保小數點右邊數字的位數,即使全部為0。可以使用流操縱符noshowpoint重置該設置
uppercase指明當顯示十六進制數時使用大寫字母,并且在科學計數法表示浮點數時使用大寫字母E。可以使用流操縱符nouppercase來重置該設置
showpos在正數(負數本來就會顯示符號)前顯示加號(+)。可以使用流操縱符noshowpos來重置該設置
scientific以科學計數法顯示輸出浮點數
fixed以定點小數形式顯示浮點數,并指定小數點右邊的位數

1.尾數零和小數點(showpoint)

流操縱符showpoint強制要求浮點數的輸出必須帶小數點和尾數零。比如說浮點數79.0,在不使用showpoint時顯示79,使用showpoint時則顯示79.0000(尾數零取決于當前的精確度)。要重置showpoint的設定,需要使用流操縱符noshowpoint

當不使用fixedscientific時,精確度表示顯示的有效位數,而不是小數點后的數字的位數。

#include <iostream>
using namespace std;int main()
{cout << "Before using showpoint:" << '\n';cout << "6.6600 prints as: " << 6.6600 << endl<< "6.6000 prints as: " << 6.6000 << endl<< "6.0000 prints as: " << 6.0000 << "\n\n";cout << "After using showpoint:" << '\n';cout << showpoint << "6.6600 prints as: " << 6.6600 << endl<< "6.6000 prints as: " << 6.6000 << endl<< "6.0000 prints as: " << 6.0000 << "\n\n";
}

運行結果:

在這里插入圖片描述

2.對齊(left、right和internal)

直接看下面的例子

#include <iostream>
#include <iomanip>
using namespace std;int main()
{int x = 12345;cout << "Default is right justified:" << endl<< setw(10) << x;cout << "\n\nUse std::left to left justify x:\n"<< left << setw(10) << x;cout << "\n\nUse std::internal to internal justify x:\n"<< showpos << internal << setw(10) << x;cout << "\n\nUse '*' to fill space x:\n"<< setfill('*') << setw(10) << x << endl;}

運行結果:

在這里插入圖片描述

其中在使用internal流操縱符時,還輔以showpos和setfill這兩個流操縱符,其中showpos是顯示在數字前顯示符號,setfill是設置在輸出內容比域寬小時進行填充的字符。

3.內容填充(fill和setfill)

成員函數fill指定對齊域的填充字符。如果沒有字符被指定,則默認使用空格符填充。fill函數返回設定之前的填充字符。setfill流操縱符也用于設置填充字符。

可以參照上一個示例代碼。

其中成員函數fill的使用,只需要在其前面使用一個ostream對象即可,例如:cout.fill('*');

4.整數流的基數

使用流操縱符showbase可以要求整數的基數被輸出。

例如:

#include <iostream>
using namespace std;int main()
{int x = 100;cout << "Printing integers preceded by their base:" << endl<< showbase;cout << x << endl;cout << oct << x << endl;cout << hex << x << endl;
}

運行結果:

在這里插入圖片描述

5.浮點數、科學計數法和定點小數記數法(scientific、fixed)

“黏性”流操縱符scientificfixed可以控制浮點數的輸出格式。流操縱符scientific要求浮點數以科學計數法的格式輸出。流操縱符fixed要求浮點數以指定小數位數的形式顯示(可以使用成員函數precision或流操縱符setprecision指定小數位數)。如果不使用其他操縱符,由浮點數的值決定浮點數的輸出格式。

使用示例:

#include <iostream>
using namespace std;int main()
{double x = 0.001234567;double y = 1.946e9;cout << "Displayed in default format:\n"<< x << '\t' << y << endl;cout << "\nDisplayed in scientific format:\n"<< scientific << x << '\t' << y << endl;cout << "\nDisplayed in fixed format:\n"<< fixed << x << '\t' << y << endl;
}

運行結果:

在這里插入圖片描述

6.大寫/小寫控制(uppercase)

流操縱符uppercase在輸出十六進制整數基數和科學計數格式的浮點數時,分別輸出大寫字母X和E。還可以使十六進制整數中的字母都以大寫字母形式顯式。在默認情況下,十六進制和科學計數格式的浮點數中的字母都以小寫字母顯示。如果要取消uppercase的設置,只需要輸出流操縱符nouppercase即可。

使用示例:

#include <iostream>
using namespace std;int main()
{cout << "Printing uppercase letters in scientific" << endl<< "notation exponents and hexadecimal values:" << endl;cout << uppercase << 4.28e10 << endl<< hex << showbase << 123456789 << endl;
}

運行結果:

在這里插入圖片描述

7.指定布爾類型(boolalpha)

boolalphanoboolalpha的設置為“黏性”的。直接看下面的示例:

#include <iostream>
using namespace std;int main()
{bool booleanValue = true;cout << "booleanValue is " << booleanValue << endl;cout << "booleanValue (after using boolalpha) is "<< boolalpha << booleanValue << "\n\n";cout << "\nswitch booleanValue and use noboolalpha" << endl;booleanValue = false;cout << noboolalpha << endl;cout << "booleanValue is " << booleanValue << endl;cout << "booleanValue (after using boolalpha) is " << boolalpha << booleanValue << endl;
}

運行結果:

在這里插入圖片描述

8.通過成員函數flags設置和重置格式狀態

通過上面的學習,我們已經知道了如何使用流操縱符來更改輸出格式,那么我們在使用了流操縱符設置了格式之后,要如何將輸出格式重置為默認狀態呢?
無參數的成員函數flags將當前的格式設置以fmtflags數據類型(ios_base類中的)的形式返回,它表示了格式狀態。
擁有一個fmtflags參數的成員函數flags將格式狀態設置為其參數指定的格式狀態,并返回之前的狀態設定。
在這里插入圖片描述

使用示例:

#include <iostream>
using namespace std;int main()
{int integerValue = 1000;double doubleValue = 0.0947628;// 顯示當前的格式狀態cout << "The value of the flags variable is: " << cout.flags()<< "\nPrint int and double in original format:\n"<< integerValue << '\t' << doubleValue << "\n\n";ios_base::fmtflags originalFormat = cout.flags();cout << showbase << oct << scientific; // 改變格式cout << "The value of the flags variable is: " << cout.flags()<< "\nPrint int and double in new format:\n"<< integerValue << '\t' << doubleValue << "\n\n";cout.flags(originalFormat); // 重置格式狀態cout << "The restored value of the flags variable is: " << cout.flags()<< "\nPrint values in original format again:\n"<< integerValue << '\t' << doubleValue << "\n\n";
}

運行結果:

在這里插入圖片描述

七、流的錯誤狀態

流的狀態可以通過檢測ios_base類中的相應位來判斷。
在這里插入圖片描述
注意,在絕大多數情況下,如果eofbit被設置了,那么failbit也會被設置。

#include <iostream>
using namespace std;int main()
{cout << "Before a bad input operation:"<< "\ncin.rdstate(): " << cin.rdstate()<< "\ncin.eof(): " << cin.eof()<< "\ncin.fail(): " << cin.fail()<< "\ncin.bad(): " << cin.bad()<< "\ncin.good(): " << cin.good() << "\n\n";int number;cout << "Expects an integer, but enter a character: ";cin >> number;cout << "\nAfter a bad input operation:"<< "\ncin.rdstate(): " << cin.rdstate()<< "\ncin.eof(): " << cin.eof()<< "\ncin.fail(): " << cin.fail()<< "\ncin.bad(): " << cin.bad()<< "\ncin.good(): " << cin.good() << "\n\n";cin.clear(); // 重置錯誤狀態,該函數的默認參數是std::ios_base::goodbitcout << "After cin.clear()" << "\ncin.rdstate(): " << cin.rdstate()<< "\ncin.eof(): " << cin.eof()<< "\ncin.fail(): " << cin.fail()<< "\ncin.bad(): " << cin.bad()<< "\ncin.good(): " << cin.good() << "\n\n";
}

運行結果:

在這里插入圖片描述

當遇到文件尾時,輸入流有eofbit將被設置。當試圖越過流的末尾提取數據時,程序可以調用成員函數eof來判斷是否遇到了文件尾。遇到文件尾返回true,否則返回false

當在流中發生格式錯誤時,failbit位將被設置,并且不會讀入任何字符,例如,像上面的測試程序一樣,預期從流中接收一個整數,但是接收到一個字符,在遇到這種情況時,這些字符不會丟失。成員函數fail將報告流操作是否失敗了。通常這種錯誤是可恢復的(數據沒有丟失)。

當發生數據丟失錯誤時,將會設置badbit位。成員函數bad將報告流操作是否失敗了。一般情況下,這種嚴重的錯誤是不可恢復的(數據已經丟失)。

如果流中的eofbit、failbit、badbit都沒有被設置,那么goodbit將設置。

成員函數rdstate返回流的錯誤狀態。可以使用該函數的返回值來判斷錯誤狀態,例如,將該函數的返回值與不同的錯誤位進行"相與",結果為1的即是出現錯誤的狀態位。

成員函數clear重置流的錯誤狀態,默認參數為goodbit,既將流的狀態設為good
所以也可以使用下面的語句將流的狀態設為錯誤cout.clear(ios::failbit);

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/83747.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/83747.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/83747.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenCV 圖像像素的邏輯操作

一、知識點 1、圖像像素的邏輯操作&#xff0c;指的是位操作bitwise&#xff0c;與、或、非、異或等。 2、位操作簡介: 位1 位2 與and 或or 異或xor0 0 0 0 00 1 0 1 11 0 0 …

【AAOS】【源碼分析】用戶管理(二)-- 整體架構

整體介紹 Android多用戶功能作為 Android Automotive 的重要組成部分,為不同駕駛員和乘客提供了一個更加定制化、隱私保護的使用環境。Android 多用戶的存在,它可以讓多個用戶使用同一臺設備,同時保持彼此的數據、應用和設置分隔開來。 各用戶類型的權限 能力SystemAdminS…

Redis最佳實踐——電商應用的性能監控與告警體系設計詳解

Redis 在電商應用的性能監控與告警體系設計 一、原子級監控指標深度拆解 1. 內存維度監控 核心指標&#xff1a; # 實時內存組成分析&#xff08;單位字節&#xff09; used_memory: 物理內存總量 used_memory_dataset: 數據集占用量 used_memory_overhead: 管理開銷內存 us…

多模態大語言模型arxiv論文略讀(109)

Math-PUMA: Progressive Upward Multimodal Alignment to Enhance Mathematical Reasoning ?? 論文標題&#xff1a;Math-PUMA: Progressive Upward Multimodal Alignment to Enhance Mathematical Reasoning ?? 論文作者&#xff1a;Wenwen Zhuang, Xin Huang, Xiantao Z…

web3-以太坊智能合約基礎(理解智能合約Solidity)

以太坊智能合約基礎&#xff08;理解智能合約/Solidity&#xff09; 無需編程經驗&#xff0c;也可以幫助你了解Solidity獨特的部分&#xff1b;如果本身就有相應的編程經驗如java&#xff0c;python等那么學起來也會非常的輕松 一、Solidity和EVM字節碼 實際上以太坊鏈上儲存…

D2-基于本地Ollama模型的多輪問答系統

本程序是一個基于 Gradio 和 Ollama API 構建的支持多輪對話的寫作助手。相較于上一版本&#xff0c;本版本新增了對話歷史記錄、Token 計數、參數調節和清空對話功能&#xff0c;顯著提升了用戶體驗和交互靈活性。 程序通過抽象基類 LLMAgent 實現模塊化設計&#xff0c;當前…

傳統業務對接AI-AI編程框架-Rasa的業務應用實戰(2)--選定Python環境 安裝rasa并初始化工程

此篇接續上一篇 傳統業務對接AI-AI編程框架-Rasa的業務應用實戰&#xff08;1&#xff09;--項目背景即學習初衷 1、Python 環境版本的選擇 我主機上默認的Python環境是3.12.3 &#xff08;我喜歡保持使用最新版本的工具或框架&#xff0c;當初裝python時最新的穩定版本就是…

Ubuntu22.04安裝MinkowskiEngine

MinkowskiEngine簡介 Minkowski引擎是一個用于稀疏張量的自動微分庫。它支持所有標準神經網絡層&#xff0c;例如對稀疏張量的卷積、池化和廣播操作。 MinkowskiEngine安裝 官方源碼鏈接&#xff1a;GitHub - NVIDIA/MinkowskiEngine: Minkowski Engine is an auto-diff neu…

高等數學基礎(矩陣基本操作轉置和逆矩陣)

矩陣是否相等 若 A A A和 B B B為同型矩陣且對應位置的各個元素相同, 則稱矩陣 A A A和 B B B相等 在Numpy中, 可以根據np.allclose()來判斷 import numpy as npA np.random.rand(4, 4) # 生成一個隨機 n x n 矩陣B A A.Tprint("矩陣是否相等&#xff1a;", np…

網絡爬蟲一課一得

網頁爬蟲&#xff08;Web Crawler&#xff09;是一種自動化程序&#xff0c;通過模擬人類瀏覽行為&#xff0c;從互聯網上抓取、解析和存儲網頁數據。其核心作用是高效獲取并結構化網絡信息&#xff0c;為后續分析和應用提供數據基礎。以下是其詳細作用和用途方向&#xff1a; …

MATLAB實現井字棋

一、智能決策系統與博弈游戲概述 &#xff08;一&#xff09;智能決策系統核心概念 智能決策系統&#xff08;Intelligent Decision System, IDS&#xff09;是通過數據驅動和算法模型模擬人類決策過程的計算機系統&#xff0c;核心目標是在復雜環境中自動生成最優策略&#…

解決el-select選擇框右側下拉箭頭遮擋文字問題

如圖所示&#xff1a; el-select長度較短的時候&#xff0c;選擇框右側下拉箭頭會遮擋選中的數據 選中數據被遮擋 解決辦法&#xff1a; 組件如下&#xff1a; <td class"fmtd" :colspan"col.ptproCupNum" v-for"col in row" :key"…

【Linux】pthread多線程同步

參考文章&#xff1a;https://blog.csdn.net/Alkaid2000/article/details/128121066 一、線程同步 線程的主要優勢在于&#xff0c;能夠通過全局變量來共享信息。不過&#xff0c;這種便攜的共享是有代價的&#xff1b;必須確保多個線程不會同時修改同一變量&#xff0c;或者某…

Spring框架學習day7--SpringWeb學習(概念與搭建配置)

SpringWeb1.SpringWeb特點2.SpringWeb運行流程3.SpringWeb組件4.搭建項目結構圖&#xff1a;4.1導入jar包4.2在Web.xml配置**4.2.1配置統一攔截分發器 DispatcherServlet**4.2.2開啟SpringWeb注解&#xff08;spring.xml&#xff09; 5.處理類的搭建6.SpringWeb請求流程(自己理…

業務到解決方案構想

解決方案構想的核心理解 解決方案構想是連接業務需求與技術實現的關鍵橋梁&#xff0c;從您描述的內容和我的理解&#xff0c;這個階段的核心點包括&#xff1a; 核心要點解讀 轉化視角&#xff1a;將業務視角的需求轉變為解決方案視角 業務能力探索階段識別了"做什么&q…

jvm學習第1day jvm簡介,棧溢出、堆溢出

jvm學習第1day jvm簡介&#xff0c;棧溢出、堆溢出 jvm簡介棧線程安全棧溢出線程運行診斷堆堆溢出 方法區方法區內存溢出常量池和運行時常量池 jvm簡介 jvm 是編譯后的字節碼文件運行的環境&#xff0c; 因此各個平臺有了jvm可以運行java.class文件&#xff0c;這是Java跨平臺…

關于神經網絡中的激活函數

這篇博客主要介紹一下神經網絡中的激活函數以及為什么要存在激活函數。 首先&#xff0c;我先做一個簡單的類比&#xff1a;激活函數的作用就像給神經網絡里的 “數字信號” 加了一個 “智能閥門”&#xff0c;讓機器能學會像人類一樣思考復雜問題。 沒有激活i函數的神經網絡…

免費無限使用GPT Plus、Claude Pro、Grok Super、Deepseek滿血版

滲透智能-ShirtAI&#xff0c;可以免費無限使用GPT Plus、Claude Pro、Grok Super、Deepseek滿血版、除此之外還能免費使用AI搜索、Gemini AI、AI照片修復、AI橡皮擦、AI去背景、AI智能摳圖、AI證件照、OCR識別、在線思維導圖、在線繪圖工具、PDF工具箱、PDF翻譯。 傳送入口&a…

阿里云 Linux 搭建郵件系統全流程及常見問題解決

阿里云 Linux 搭建 [conkl.com]郵件系統全流程及常見問題解決 目錄 阿里云 Linux 搭建 [conkl.com]郵件系統全流程及常見問題解決一、前期準備&#xff08;關鍵配置需重點檢查&#xff09;1.1 服務器與域名準備1.2 系統初始化&#xff08;必做操作&#xff09; 二、核心組件安裝…

python版若依框架開發:項目結構解析

python版若依框架開發 從0起步&#xff0c;揚帆起航。 python版若依部署代碼生成指南&#xff0c;迅速落地CURD&#xff01;項目結構解析 文章目錄 python版若依框架開發前端后端 前端 后端