程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 深入淺出scanf、getcha、gets、cin函數,getchacin

深入淺出scanf、getcha、gets、cin函數,getchacin

編輯:關於C語言

深入淺出scanf、getcha、gets、cin函數,getchacin


轉:問題描述一:(分析scanf()和getchar()讀取字符)  


    scanf(), getchar()等都是標准輸入函數,一般人都會覺得這幾個函數非常簡單,沒什麼特殊的。但是有時候卻就是因為使用這些函數除了問題,卻找不出其中的原因。下面先看一個很簡單的程序:
程序1:
    #include <stdio.h>
    int main()
    {
char ch1, ch2;
scanf("%c", &ch1); 
scanf("%c", &ch2);
printf("%d %d\n", ch1, ch2);
return 0;
    }
    或者是:
    #include <stdio.h>
    int main()
    {
char ch1, ch2;
ch1 = getchar();
ch2 = getchar();
printf("%d %d\n", ch1, ch2);
return 0;
    }
    程序的本意很簡單,就是從鍵盤讀入兩個字符,然後打印出這兩個字符的ASCII碼值。可是執行程序後會發現除了問題:當從鍵盤輸入一個字符後,就打印出了結果,根本就沒有輸入第二個字符程序就結束了。例如用戶輸入字符'a', 打印結果是97,10。這是為什麼呢?
【分析】:
    首先我們呢看一下輸入操作的原理, 程序的輸入都建有一個緩沖區,即輸入緩沖區。一次輸入過程是這樣的,當一次鍵盤輸入結束時會將輸入的數據存入輸入緩沖區,而cin函數直接從輸入緩沖區中取數據。正因為cin函數是直接從緩沖區取數據的,所以有時候當緩沖區中有殘留數據時,cin函數會直接取得這些殘留數據而不會請求鍵盤輸入,這就是例子中為什麼會出現輸入語句失效的原因!
    其實這裡的10恰好是回車符!這是因為scanf()和getchar()函數是從輸入流緩沖區中讀取值的,而並非從鍵盤(也就是終端)緩沖區讀取。而讀取時遇到回車(\n)而結束的,這個\n會一起讀入輸入流緩沖區的,所以第一次接受輸入時取走字符後會留下字符\n,這樣第二次的讀入函數直接從緩沖區中把\n取走了,顯然讀取成功了,所以不會再從終端讀取!這就是為什麼這個程序只執行了一次輸入操作就結束的原因!

----------------------------------------------------
| 問題描述二:(分析scanf()和gets()讀取字符串)   |
----------------------------------------------------
首先我們看一下scanf()讀取字符串的問題:
程序2:
    #include <stdio.h>
    int main()
    {
char str1[20], str2[20];
scanf("%s",str1); 
printf("%s\n",str1);    
scanf("%s",str2); 
printf("%s\n",str2); 
return 0;
    }
    程序的功能是讀入一個字符串輸出,在讀入一個字符串輸出。可我們會發現輸入的字符串中不能出現空格,例如:
測試一輸入:
Hello world!
輸出:
Hello
world!
【分析】到此程序執行完畢,不會執行第二次的讀取操作!這個問題的原因跟問題一類似,第一次輸入Hello world!後,字符串Hello world!都會被讀到輸入緩沖區中,而scanf()函數取數據是遇到回車、空格、TAB就會停止,也就是第一個scanf()會取出"Hello",而"world!"還在緩沖區中,這樣第二個scanf會直接取出這些數據,而不會等待從終端輸入。

測試二:
Hello[Enter] 
Hello[輸出]
world[Enter]
world[輸出]
【分析】程序執行了兩次從鍵盤讀入字符串,說明第一次輸入結束時的回車符被丟棄!即:scanf()讀取字符串會捨棄最後的回車符!


我們再看一下gets()讀取字符串的情況:
用scanf來讀取一個字符串時,字符串中是不可以出現空格的,一旦出現空格,後面的數據就會捨棄殘留在緩沖區中。其實有另外一個函數是可以接受空格的,那就是gets(),下面我們看一下這個函數的應用,我們把程序2改動一下:
程序3:
#include <stdio.h>
int main()
{
char str1[20], str2[20];
gets(str1); 
printf("%s\n",str1);    
gets(str2); 
printf("%s\n",str2); 
return 0;
}
測試:
Hello world! [輸入]
Hello world! [輸出]
12345 [輸入]
12345 [輸出]
【分析】顯然與上一個程序的執行情況不同,這次程序執行了兩次從鍵盤的讀入,而且第一個字符串取了Hello world! 接受了空格符,而沒有像上一個程序那樣分成了兩個字符串!所以如果要讀入一個帶空格符的字符串時因該用gets(), 而不宜用scanf()!


--------------------------------------------------------
| 問題描述三:(getchar()暫停程序,查看程序執行結果)|
--------------------------------------------------------
    不知道大家有沒有遇到過這樣的問題,有的編譯器程序執行完後的結果界面不會停下而是一閃就沒了,以至於看不到執行結果。所以很多人在程序最後加上getchar()語句,目的是想讓程序執行完後停下來,等待從終端接收一個字符再結束程序。可是發現有時候這樣根本沒用,程序照樣跳出去了。這是為什麼呢?
【分析】原因跟上面例子講的一樣,是因為輸入緩沖區中還有數據,所以getchar()會成果讀到數據,所以就跳出了!

------------------
|     【總結】    |
------------------
第一:要注意不同的函數是否接受空格符、是否捨棄最後的回車符的問題!
讀取字符時:
scanf()以Space、Enter、Tab結束一次輸入,不會捨棄最後的回車符(即回車符會殘留在緩沖區中);
getchar()以Enter結束輸入,也不會捨棄最後的回車符;
讀取字符串時:
scanf()以Space、Enter、Tab結束一次輸入
gets()以Enter結束輸入(空格不結束),接受空格,會捨棄最後的回車符!

第二:為了避免出現上述問題,必須要清空緩沖區的殘留數據,可以用以下的方法解決:
方法1:C語言裡提供了函數清空緩沖區,只要在讀數據之前先清空緩沖區就沒問題了!
       這個函數是fflush(stdin)。
方法2:自己取出緩沖區裡的殘留數據。
(說實話這個語句我也沒看懂,呵呵!為什麼格式控制是這樣的!希望高手指點一下!)
       scanf("%[^\n]",string);

 

C/C++學習筆記2 - cin深入分析(上) - cin輸入操作處理

cin<<, cin.get,cin.getline等函數深入分析

很多初學者都認為cin函數是一個很簡單的函數,其實不然!cin函數有很多需要了解的知識(比如:cin的返回值是什麼,cin提供了哪些成員函數且分別是什麼作用,如cin.clear(), cin.ignore(), cin.fail(), cin.good()等等),如果沒有很好的掌握,在使用的時候很可能會出問題卻不知其原因!而且很多人也確確實實遇到過不少問題,以下是幾個簡單的例子:

程序1:

#include <iostream>

using namespace std;

int main()

{

       int m, n;

       cin>>m;

    cin>>n;

       return 0;

}

測試情況:

如果用戶每次都輸入兩個合法的數,程序不會出問題!

但是如果用戶第一次輸入時給一個非法的輸入,比如說輸入一個字符'a',你會發現程序不

會再執行第二條輸入語句。似乎有點奇怪!!

程序2:

#include <iostream>

using namespace std;

int main()

{

       char str[8];

       cin.getline(str, 5);

       cout<<str<<endl;

       cin.getline(str, 5);

       cout<<str<<endl;

       return 0;

}

程序的功能很簡單,就是輸入一個字符串再輸出,再次輸入一個字符串輸出。程序執行情況:

測試一:

abcd (回車)

abcd (輸出)

efgh (回車)

efgh (輸出)

當用戶第一次輸入的字符串字符數小於4時,程序執行正常!

測試二:

abcdefgh (回車)

abcd (輸出)

     (輸出-換行)

當用戶第一次輸入的字符數字符數大於4時,第一個字符串接受輸入的前四個字符,而第二次的輸入操作沒有執行,第二個字符串輸出為空。似乎也很奇怪!!!

其實在很多時候都會遇到諸如此類的問題,如果不熟悉程序輸入的原理和cin等一些函數的原理就不知道怎麼解決!我在這裡做一個簡單的介紹,也許介紹得不是很准確和全面,或者存在一些誤解,請大家包涵!

輸入操作的原理

與前一節中提到的scanf函數一樣,程序的輸入都建有一個緩沖區,即輸入緩沖區。一次輸入過程是這樣的,當一次鍵盤輸入結束時會將輸入的數據存入輸入緩沖區,而cin函數直接從輸入緩沖區中取數據。正因為cin函數是直接從緩沖區取數據的,所以有時候當緩沖區中有殘留數據時,cin函數會直接取得這些殘留數據而不會請求鍵盤輸入,這就是例子中為什麼會出現輸入語句失效的原因!

cin的一些輸入函數和操作符

cin is a extern istream object。提供了很多可用的成員函數和重載的操作符,如:cin<<, cin.get(), cin.getline()等。下面我們來了解一下這幾個函數:

一. cin<<

該操作符是根據後面變量的類型讀取數據。

輸入結束條件   :遇到Enter、Space、Tab鍵。(這個很重要!)

對結束符的處理 :丟棄緩沖區中使得輸入結束的結束符(Enter、Space、Tab)

讀字符的情況:

程序3:

#include <iostream>

using namespace std;

int main()

{

       char c1, c2;

       cin>>c1;

       cin>>c2;

       cout<<c1<<" "<<c2<<endl;

       return 0;

}

測試一輸入:

a[Enter]

b[Enter]

輸出:

a b

測試二輸入:

a b[Enter]

輸出:

a b

  

讀字符串的情況:

程序4:

#include <iostream>

using namespace std;

int main()

{

       char str1[10], str2[10];

       cin>>str1;

       cin>>str2;

       cout<<str1<<endl;

       cout<<str2<<endl;

       return 0;

}

測試一輸入:

abcd[Enter]

efgh[Enter]

輸出:

abcd

efgh

【分析】輸入遇到回車符結束,很正常。

測試二輸入:

abcd efgh

輸出:

abcd

efgh

【分析】第一次讀取字符串時遇到空格則停止了,將abcd讀入str1,並捨棄了空格,將後面的字符串給了第二個字符串。這證明了cin讀入數據遇到空格結束;並且丟棄空格符;緩沖區有殘留數據室,讀入操作直接從緩沖區中取數據。

  

二.cin.get()

該函數有三種格式:無參,一參數,二參數

即cin.get(), cin.get(char ch), cin.get(array_name, Arsize)

讀取字符的情況:

輸入結束條件:Enter鍵

對結束符處理:不丟棄緩沖區中的Enter

cin.get() 與 cin.get(char ch)用於讀取字符,他們的使用是相似的,

即:ch=cin.get() 與 cin.get(ch)是等價的。

程序5:

#include <iostream>

using namespace std;

int main()

{

       char c1, c2;

       cin.get(c1);

       cin.get(c2);

       cout<<c1<<" "<<c2<<endl;   // 打印兩個字符

       cout<<(int)c1<<" "<<(int)c2<<endl; // 打印這兩個字符的ASCII值

       return 0;

}

測試一輸入:

a[Enter]

輸出:

a

97 10

【分析】會發現只執行了一次從鍵盤輸入,顯然第一個字符變量取的'a', 第二個變量取的是Enter(ASCII值為10),這是因為該函數不丟棄上次輸入結束時的Enter字符,所以第一次輸入結束時緩沖區中殘留的是上次輸入結束時的Enter字符!

測試二輸入:

a b[Enter]

輸出:

a

97 32

【分析】顯然第一個字符變量取的'a', 第二個變量取的是Space(ASCII值為32)。原因同上,沒有丟棄Space字符。

讀取字符串的情況:

cin.get(array_name, Arsize)是用來讀取字符串的,可以接受空格字符,遇到Enter結束輸入,按照長度(Arsize)讀取字符, 會丟棄最後的Enter字符。

程序6:

#include <iostream>

using namespace std;

int main ()

{

char a[20];

cin.get(a, 10);

cout<<a<<endl;

return 0;

}

測試一輸入:

abc def[Enter]

輸出:

abc def

【分析】說明該函數輸入字符串時可以接受空格。

測試二輸入:

1234567890[Enter]

輸出:

123456789

【分析】輸入超長,則按需要的長度取數據。

程序7:

#include <iostream>

using namespace std;

int main ()

{

char ch, a[20];

cin.get(a, 5);

cin>>ch;

cout<<a<<endl;

cout<<(int)ch<<endl;

return 0;

}

測試一輸入:

12345[Enter]

輸出:

1234

53

【分析】第一次輸入超長,字符串按長度取了"1234",而'5'仍殘留在緩沖區中,所以第二次輸入字符沒有從鍵盤讀入,而是直接取了'5',所以打印的ASCII值是53('5'的ASCII值)。

測試二輸入:

1234[Enter]

a[Enter]

輸出:

1234

97

【分析】第二次輸入有效,說明該函數把第一次輸入後的Enter丟棄了!

  

三.cin.getline()

cin.getline() 與 cin.get(array_name, Arsize)的讀取方式差不多,以Enter結束,可以接受空格字符。按照長度(Arsize)讀取字符, 會丟棄最後的Enter字符。

但是這兩個函數是有區別的:

cin.get(array_name, Arsize)當輸入的字符串超長時,不會引起cin函數的錯誤,後面的cin操作會繼續執行,只是直接從緩沖區中取數據。但是cin.getline()當輸入超長時,會引起cin函數的錯誤,後面的cin操作將不再執行。(具體原因將在下一部分"cin的錯誤處理"中詳細介紹)

程序8:

#include <iostream>

using namespace std;

int main ()

{

char ch, a[20];

cin.getline(a, 5);

cin>>ch;

cout<<a<<endl;

cout<<(int)ch<<endl;

return 0;

}

測試輸入:

12345[Enter]

輸出:

1234

-52

【分析】與cin.get(array_name, Arsize)的例程比較會發現,這裡的ch並沒有讀取緩沖區中的5,而是返回了-52,這裡其實cin>>ch語句沒有執行,是因為cin出錯了!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved