1. 程式人生 > >C++中cout、cin和endl的用法

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是