C++ 格式化IO
引言
昨天筆試騰訊後,收穫不少,雖然比上次網易的情況略好一些,但是感覺自己的coding能力還是不夠,在高壓力情況下的心理素質不過關。本文順帶總結一下筆試中遇到的C++格式化輸出問題,當時由於緊張和對知識的不熟悉,對這道簡單的格式化輸出竟然留了空白,真是太虧了。下面開始正文。
C++一般採用cout進行格式化輸出,包含標頭檔案< iomanip >可以實現幾乎所有你想要的格式化輸出。主要包括:
- 操縱不同型別的格式
- 浮點數輸出精度和科學計數法
- 定寬輸出(包括填充符號)
未格式化流的讀取
操縱不同型別的格式
對於不同型別的格式,可以使用操作符改變格式狀態。
整型變數
可以按不同進位制輸出:
int val = 17;
cout<<oct<<val<<endl; //輸出21
cout<<hex<<val<<endl; //輸出11
cout<<dec<<val<<endl; //輸出17
//可以使用showbase操作符顯示進位制
cout<<showbase;
cout<<oct<<val<<endl; //輸出021
cout<<hex<<val<<endl; //輸出0x11
cout<<dec<<val<<endl; //輸出17
cout<<noshowbase;//關閉顯示進位制
注意,這些操縱符會改變內部狀態,對之後的輸出也會產生影響。
布林型變數
可以使用boolalpha操作符改變cout輸出bool變數的格式,如:
cout<<boolalpha;
cout<<true<<endl;//輸出true
cout<<false<<endl;//輸出false
cout<<noboolalpha;
浮點型變數
對於浮點型變數我們可以控制幾種格式,包括:
- 浮點數精度
- 輸出進位制和是否採用科學計數法
- 對於沒有小數的部分是否列印小數點
浮點數精度可以通過setprecision操縱符或改變cout.precision的值來控制,如:
cout <<sqrt(2)<< endl; //預設保持6位精度(包括整數部分),故輸出1.41421
cout << setprecision(4) <<sqrt(2)<< endl;//輸出1.414
//當浮點數小樹部分為0,可以使用showpoint操縱符顯示小數部分,如果浮點數顯示未達到當前精度,也可以使用showpoint來補全小數後的0
cout <<setprecision(4)<<showpoint<<17.0<< endl;//輸出17.00
浮點數也能指定輸出的進位制和是否採用科學計數法,預設輸出為小寫字母,可以採用uppercase改為大寫輸出:
cout<<hexfloat<<17.0<<endl;//輸出0x1.100000p+4
cout<<scientific<<17.0<<endl;//輸出1.700000e+001
//注意,通過scientific或hexfloat或fixed(預設十進位制)操作符後,會改變精度的定義,精度將定義為小數點後的位數,而預設為總位數
輸出補白
處理資料時,我們經常需要對齊資料,因此定寬輸出和補白是一種很常用的功能。C++提供了setw,setfill,left,right,internal等操作符控制輸出的對齊和補白,如:
int val = 10;
cout<<setw(8)<<val<<endl;//輸出 10
//預設右對齊用空白字元補白
cout<<setw(8)<<left<<setfill('#')<<val<<endl;//輸出 10######
//我們通過left操作符將輸出改為左對齊,setfill操作符更改預設的補白字元
cout<<setw(8)<<internal<<setfill('#')<<showpos<<val<<endl;//輸出+#####10
//這裡主要解釋一下internal操作符和showpos操作符,對於數值型輸出時,使用internal操作符將在符號與數值之間補白,而showpos操作符則顯示正數的符號,因此就得到了上述輸出。
需要注意的是,setw不改變內部狀態,它只決定下一個輸出的寬度。
控制輸入格式
預設情況下,cin會跳過空白符,製表符,回車符,換行符,換頁符,可以通過操作符noskipws讀取空白符:
char c;
while(cin>>c)
cout<<c;
//輸入"ab c d",輸出abcd
while(cin>>noskipws>>c)
cout<<c;
//輸入"ab c d",輸出ab c d
未格式化IO
之前我們提到的輸入輸出都是利用>>或者<<根據讀取或輸入的資料型別進行格式化。
標準庫還提供了對未格式化資料的IO操作,這些操作將資料當作位元組序列進行處理。
單位元組操作
未格式化IO提供get和put分別用於輸入和輸出單個字元,他們也會讀取空白字元,因為未格式化的操作來說,每個字元只是沒有意義的數字而已:
char c;
while (cin.get(c))
cout.put(c);//能夠讀取空白符,回車符等所有字元
若想一次性讀取大塊未格式化的資料,可以使用get的過載函式cin.get(sink,size,delimiter) 從
cin中讀取最多size個位元組,並儲存在首地址為sink的字元陣列中。讀取過程直到遇到delimiter或檔案終止結束。如果遇到delimiter結束,則將其保留delimiter中,不讀取出來。一個類似的函式是cin.getline(sink,size,delimiter)
兩個方法的區別在於getline會讀取delimiter並丟棄。
小結
一般情況下我們採用格式化IO不容易出錯,儘量不採用未格式化IO。格式化IO提供了包括整型,浮點型,布林型等型別的輸出控制,還有通用的資料對齊,輸出補白等常用功能。對於日常使用來說,這已經足夠了。