C++中cout、cin和endl的用法
轉自:http://blog.163.com/ac_victory/blog/static/1033187262008112222553105/
對以上三篇文章,我添加了自己已有的部分知識,並重新地彙總整理
輸入和輸出並不是C++語言中的正式組成成分。C和C++本身都沒有為輸入和輸出提供專門的語句結構。輸入輸出不是由C++本身定義的,而是在編譯系統提供的I/O庫中定義的。
C++的輸出和輸入是用“流”(stream)的方式實現的。圖3.2和圖3.3表示C++通過流進行輸入輸出的過程。
有關流物件cin、cout和流運算子的定義等資訊是存放在C++的輸入輸出流庫中的,因此如果在程式中使用cin、cout和流運算子,就必須使用預處理命令把標頭檔案stream包含到本檔案中:
#include <iostream>
儘管cin和cout不是C++本身提供的語句,但是在不致混淆的情況下,為了敘述方便,常常把由cin和流提取運算子“>>”實現輸入的語句稱為輸入語句或cin語句,把由cout和流插入運算子“<<”實現輸出的語句稱為輸出語句或cout語句。根據C++的語法,凡是能實現某種操作而且最後以分號結束的都是語句。
一 輸入流與輸出流的基本操作
cout語句的一般格式為:
cout<<表示式1<<表示式2<<……<<表示式n;
cin語句的一般格式為:
cin>>變數1>>變數2>>……>>變數n;
在定義流物件,系統會在記憶體中開闢一段緩衝區,用來暫存輸入輸出流的資料。在執行cout語句時,先把插入的資料順序存放在輸出緩衝區中,直到輸出緩衝區滿或遇到cout語句中的endl(或‘\n’,ends,flush)為止,此時將緩衝區中已有的資料一起輸出,並清空緩衝區。輸出流中的資料在系統預設的裝置(一般為顯示器)輸出。
1.1 cout多行格式
一個cout語句可以分寫成若干行。如cout<<"This is a simple C++ program."<<endl;
可以寫成
cout<<"This is " //注意行末尾無分號
<<"a C++ "
<<"program."
<<endl; //語句最後有分號
也可寫成多個cout語句,即
cout<<"This is "; //語句末尾有分號
cout <<"a C++ ";
cout <<"program.";
cout<<endl;
以上3種情況的輸出均為
This is a simple C++ program.
注意 不能用一個插入運算子“<<”插入多個輸出項,如:
cout<<a,b,c; //錯誤,不能一次插入多項
cout<<a+b+c; //正確,這是一個表示式,
作為一項
1.2 cout輸出型別
在用cout輸出時,使用者不必通知計算機按何種型別輸出,系統會自動判別輸出資料的型別,使輸出的資料按相應的型別輸出。如已定義a為int型,b為float型,c為char型,則cout<<a<<' '<<b<<' '<<c<<endl;
會以下面的形式輸出:
4 345.789 a
1.3 cin多行格式
與cout類似,一個cin語句可以分寫成若干行。如cin>>a>>b>>c>>d;
可以寫成
cin>>a //注意行末尾無分號
>>b //這樣寫可能看起來清晰些
>>c
>>d;
也可以寫成
cin>>a;
cin>>b;
cin>>c;
cin>>d;
以上3種情況均可以從鍵盤輸入: 1 2 3 4 ↙
也可以分多行輸入資料:
1↙
2 3↙
4↙
在用cin輸入時,系統也會根據變數的型別從輸入流中提取相應長度的位元組。如有
char c1,c2;
int a;
float b;
cin>>c1>>c2>>a>>b;
如果輸入
1234 56.78↙
注意: 34後面應該有空格以便和56.78分隔開。也可以按下面格式輸入:
1 2 34 56.78↙ (在1和2之間有空格)
不能用cin語句把空格字元和回車換行符作為字元輸入給字元變數,它們將被跳過。如果想將空格字元或回車換行符(或任何其他鍵盤上的字元)輸入給字元變數,可以用3.4.3節介紹的getchar函式。
在組織輸入流資料時,要仔細分析cin語句中變數的型別,按照相應的格式輸入,否則容易出錯。
二 關於endl的用法
2.1 關於“ ”和’ ’的用法解析
1) "a"和'a'的區別,前者是字串,後者是字元。
2) "\n"是個const char*, 指向一個2位元組的區域,呼叫的是operator <<(const char *); 而'\n'是一個位元組的char, 呼叫的是operator <<(char). 但是效能影響很小,或者可能會被編譯器優化掉。
2.2 初級認識
1 在c++中,終端輸出換行時,用cout<<......<<endl與 “\n”都可以,這是初級的認識。但二者有小小的區別,用endl時會重新整理緩衝區,使得棧中的東西重新整理一次,但用“\n”不會重新整理,它只會換行,棧內資料沒有變化。
2 cout << endl;除了往輸出流中插入一個'\n',還有重新整理輸出流的作用。
cout <<endl; 等價於: cout<< '\n' << flush;
- 在大的程式中,建議用endl來換行。
- 在沒有必要重新整理輸出流的時候應儘量使用cout <<'\n', 過多的endl是影響程式執行效率低下的因素之一。
- “\n”與’\n’,在輸出上都是表示換行,沒有區別
2.3 深層解析
我們在最初學習C++語言時就接觸到"cout<<endl;"這樣的語句。我們都知道endl表示換行的意思。我一直習慣這樣使用,卻並不是清楚其內部實現是怎麼樣的。今天看《C++ Standard Library, Sec.13.6.1》,才真正弄明白。
首先,endl是一個操作符(Manipulators),但我們必須知道endl是一個什麼型別的變數。endl是跟在”<<“運算子後面,故endl應該是一個引數。其實endl是一個函式名,它是一個"<<"運算子過載函式中的引數,引數型別為函式指標。下面我們看下內部函式實現。
ostream& ostream::operator << ( ostream& (*op)(ostream&))
{
// call the function passed as parameter with this stream as theargument
return (*op) (*this);
}
std::ostream& std::endl (std::ostream& strm)
{
// write newline
strm.put('\n');
// flush the output buffer
strm.flush();
// return strm to allowchaining
return strm;
}
可以看出,運算子過載函式中的函式引數為一個函式指標,其指向一個輸入輸出均為ostream類引用的函式。而endl正是這樣一個函式。所以我們在執行"cout<<endl;"語句時,endl是一個函式引數,型別為函式指標。然後會執行”return (*endl) (*this);“語句,即執行endl函式。
- endl函式輸出一個換行符,並重新整理輸出緩衝區。
這樣我們知道在標準庫中endl是作為一個函式實現的,顯然我們也可以直接呼叫這一函式。我們看下面的測試程式:
#include<iostream>
using namespace std;
int main()
{
cout<<endl;
endl(cout);
return 0;
}
其輸出為兩個空行。”cout<<endl"中,endl是一個型別為函式指標的函式引數,通過運算子過載函式間接呼叫了endl函式。而“endl(cout)”中,endl是函式名,直接呼叫了endl函式。
三 在輸入流與輸出流中使用控制符
上面介紹的是使用cout和cin時的預設格式。但有時人們在輸入輸出時有一些特殊的要求,如在輸出實數時規定欄位寬度,只保留兩位小數,資料向左或向右對齊等。C++提供了在輸入輸出流中使用的控制符(有的書中稱為操縱符)。
需要注意的是:如果使用了控制符,在程式單位的開頭除了要加iostream標頭檔案外,還要加iomanip標頭檔案。
3.1 三個使用控制符的例子
例1:輸出雙精度數
double a=123.456789012345;對a賦初值
(1) cout<<a;輸出: 123.456
(2) cout<<setprecision(9)<<a;輸出: 123.456789
(3) cout<<setprecision(6);恢復預設格式(精度為6)
(4) cout<< setiosflags(ios∷fixed);輸出:123.456789
(5) cout<<setiosflags(ios∷fixed)<<setprecision(8)<<a;輸出: 123.45678901
(6) cout<<setiosflags(ios∷scientific)<<a;輸出: 1.234568e+02
(7) cout<<setiosflags(ios∷scientific)<<setprecision(4)<<a; 輸出: 1.2346e02
例2:整數輸出的
int b=123456;對b賦初值
(1) cout<<b;輸出: 123456
(2) cout<<hex<<b; 輸出: 1e240
(3) cout<<setiosflags(ios∷uppercase)<<b;輸出: 1E240
(4) cout<<setw(10)<<b<<','<<b; 輸出: 123456,123456
(5) cout<<setfill('*')<<setw(10)<<b;輸出: **** 123456
(6) cout<<setiosflags(ios∷showpos)<<b;輸出: +123456
如果在多個cout語句中使用相同的setw(n),並使用setiosflags(ios∷right),可以實現各行資料右對齊,如果指定相同的精度,可以實現上下小數點對齊。
例3: 各行小數點對齊
#include <iostream>
#include <iomanip>
using namespace std;
int main( )
{
double a=123.456,b=3.14159,c=-3214.67;
cout<<setiosflags(ios∷fixed)<<setiosflags(ios∷right)<<setprecision(2);
cout<<setw(10)<<a<<endl;
cout<<setw(10)<<b<<endl;
cout<<setw(10)<<c<<endl;
return 0;
}
輸出如下:
123.46 (欄位寬度為10,右對齊,取兩位小數)
3.14
-3214.67
先統一設定定點形式輸出、取兩位小數、右對。這些設定對其後的輸出均有效(除非重新設定),而setw只對其後一個輸出項有效,因此必須在輸出a,b,c之前都要寫setw(10)。
3.2 六個輸入函式用法
學C++的時候,這幾個輸入函式弄的有點迷糊;這裡做個小結,為了自己複習,也希望對後來者能有所幫助,如果有差錯的地方還請各位多多指教(本文所有程式均通過VC 6.0執行)轉載請保留作者資訊;
1. cin
2. cin.get()
3. cin.getline()
4. getline()
5. gets()
6. getchar()
3.2.1 cin>>
用法1:最基本,也是最常用的用法,輸入一個數字:
#include <iostream>
using namespace std;
main ()
{
int a,b;
cin>>a>>b;
cout<<a+b<<endl;
}
輸入:2[回車]3[回車]
輸出:5
用法2:接受一個字串,遇“空格”、“TAB”、“回車”都結束
#include <iostream>
using namespace std;
main ()
{
char a[20];
cin>>a;
cout<<a<<endl;
}
輸入:jkljkljkl
輸出:jkljkljkl
輸入:jkljkljkljkl //遇空格結束
輸出:jkljkl
3.2.2 cin.get()
用法1: cin.get(字元變數名)可以用來接收字元#include <iostream>
using namespace std;
main ()
{
char ch;
ch=cin.get(); //或者cin.get(ch);
cout<<ch<<endl;
}
輸入:jljkljkl
輸出:j
用法2:cin.get(字元陣列名,接收字元數目)用來接收一行字串,可以接收空格
#include <iostream>
using namespace std;
main ()
{
char a[20];
cin.get(a,20);
cout<<a<<endl;
}
輸入:jkl jkl jkl
輸出:jkl jkl jkl
輸入:abcdeabcdeabcdeabcdeabcde(輸入25個字元)
輸出:abcdeabcdeabcdeabcd (接收19個字元+1個'\0')
用法3:cin.get(無引數)沒有引數主要是用於捨棄輸入流中的不需要的字元,或者捨棄回車,彌補cin.get(字元陣列名,接收字元數目)的不足。
這個我還不知道怎麼用,知道的前輩請賜教;
3.2.3 cin.getline()
// 接受一個字串,可以接收空格並輸出#include <iostream>
using namespace std;
main ()
{
char m[20];
cin.getline(m,5);
cout<<m<<endl;
}
輸入:jkljkljkl
輸出:jklj
接受5個字元到m中,其中最後一個為'\0',所以只看到4個字元輸出;
如果把5改成20:
輸入:jkljkljkl
輸出:jkljkljkl
輸入:jklf fjlsjffjsdklf
輸出:jklf fjlsjffjsdklf
//延伸:
//cin.getline()實際上有三個引數,cin.getline(接受字串的看哦那間m,接受個數5,結束字元)
//當第三個引數省略時,系統預設為'\0'
//如果將例子中cin.getline()改為cin.getline(m,5,'a');當輸入jlkjkljkl時輸出jklj,輸入jkaljkljkl時,輸出jk
當用在多維陣列中的時候,也可以用cin.getline(m[i],20)之類的用法:
#include<iostream>
#include<string>
using namespace std;
main ()
{
char m[3][20];
for(int i=0;i<3;i++)
{
cout<<"\n請輸入第"<<i+1<<"個字串:"<<endl;
cin.getline(m[i],20);
}
cout<<endl;
for(int j=0;j<3;j++)
cout<<"輸出m["<<j<<"]的值:"<<m[j]<<endl;
}
請輸入第1個字串:
kskr1
請輸入第2個字串:
kskr2
請輸入第3個字串:
kskr3
輸出m[0]的值:kskr1
輸出m[1]的值:kskr2
輸出m[2]的值:kskr3
3.2.4 getline()
// 接受一個字串,可以接收空格並輸出,需包含“#include<string>”#include<iostream>
#include<string>
using namespace std;
main ()
{
string str;
getline(cin,str);
cout<<str<<endl;
}
輸入:jkljkljkl
輸出:jkljkljkl
輸入:jkljfksldfj jklsjfl
輸出:jkljfksldfj jklsjfl
和cin.getline()類似,但是cin.getline()屬於istream流,而getline()屬於string流,是不一樣的兩個函式
3.2.5 gets()
// 接受一個字串,可以接收空格並輸出,需包含“#include<string>”#include<iostream>
#include<string>
using namespace std;
main ()
{
char m[20];
gets(m); //不能寫成m=gets();
cout<<m<<endl;
}
輸入:jkljkljkl
輸出:jkljkljkl
輸入:jkl jkl jkl
輸出:jkl jkl jkl
類似cin.getline()裡面的一個例子,gets()同樣可以用在多維數組裡面:
#include<iostream>
#include<string>
using namespace std;
main ()
{
char m[3][20];
for(int i=0;i<3;i++)
{
cout<<"\n請輸入第"<<i+1<<"個字串:"<<endl;
gets(m[i]);
}
cout<<endl;
for(int j=0;j<3;j++)
cout<<"輸出m["<<j<<"]的值:"<<m[j]<<endl;
}
請輸入第1個字串:
kskr1
請輸入第2個字串:
kskr2
請輸入第3個字串:
kskr3
輸出m[0]的值:kskr1
輸出m[1]的值:kskr2
輸出m[2]的值:kskr3
自我感覺gets()和cin.getline()的用法很類似,只不過cin.getline()多一個引數罷了;
這裡順帶說明一下,對於本文中的這個kskr1,kskr2,kskr3的例子,對於cin>>也可以適用,原因是這裡輸入的沒有空格,如果輸入了空格,比如“ks kr jkl[回車]”那麼cin就會已經接收到3個字串,“ks,kr,jkl”;再如“kskr 1[回車]kskr 2[回車]”,那麼則接收“kskr,1,kskr”;這不是我們所要的結果!而cin.getline()和gets()因為可以接收空格,所以不會產生這個錯誤;
3.2.6 getchar()
//接受一個字元,需包含“#include<string>”#include<iostream>
#include<string>
using namespace std;
main ()
{
char ch;
ch=getchar(); //不能寫成getchar(ch);
cout<<ch<<endl;
}
輸入:jkljkljkl
輸出:j
//getchar()是C語言的函式,C++也可以相容,但是儘量不用或少用;
有什麼建議可以一起探討,我的email是