【轉載】深入瞭解scanf()/getchar()和gets()等函數,C++系列教程,C++執行個體教程,C++

來源:互聯網
上載者:User


轉載自 yongahao----------------------------------------------------
| 問題描述一:(分析scanf()和gets()讀取字元)   |
----------------------------------------------------
       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取走了,顯然讀取成功了,所以不會再從終端讀取!這就是為什麼這個程式只執行了一次輸入操作就結束的原因!       這裡再插一句:ASCII碼中的10是line feed-\n-換行,將當前位置移到下一行開頭;13是carriage return-\r-斷行符號,將當前位置移到本行開頭。

      在微軟的系統中,C程式處理文本是自動轉換這兩個符號的:

1、讀的時候將   \r\n   自動當作一個字元   \n 
2、寫的時候寫一個   \n   自動轉換為   \r\n 
     造成一種誤解,好象   \n   就是斷行符號加換行      你可以向一個檔案中寫入一個   '\n',用十六進位編輯器開啟檔案,會發現有兩個位元組   0D   0A,   就是   \r\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);//直至遇到斷行符號結束; scanf("%[^\t^\n]",string);//直至遇到tab或斷行符號結束;

再轉一篇~~~
        scanf函數的一般形式:  
       scanf(格式控制,地址表列)
       int scanf(char *format,argument,...);
       “格式控制”的含義同printf函數;“地址表列”是由若干個地址組成的表列,可以是變數的地址,或字串首地址。
       scanf()函數返回成功賦值的資料項目數,出錯時則返回EOF。

格式字元說明:
       %a,%A 讀入一個浮點值(僅C99有效)
  %c 讀入一個字元
  %d 讀入十進位整數
  %i 讀入十進位,八進位,十六進位整數
  %o 讀入八進位整數
  %x,%X 讀入十六進位整數
  %c 讀入一個字元
  %s 讀入一個字串,遇空格、定位字元或分行符號結束。
  %f,%F,%e,%E,%g,%G 用來輸入實數,可以用小數形式或指數形式輸入。
  %p 讀入一個指標
  %u 讀入一個無符號十進位整數
  %n 至此已讀入值的等價字元數
  %[] 掃描字元集合
  %% 讀%符號
  
  附加格式說明字元表修飾符說明:
  L/l 長度修飾符 輸入"長"資料
  h 長度修飾符 輸入"短"資料
  W 整型常數 指定輸入資料所佔寬度
  * 表示本輸入項在讀入後不賦值給相應的變數 
scanf的傳回值:
    scanf的傳回值有後面的參數決定,scanf("%d%d", &a, &b);
  1、如果a和b都被成功讀入,那麼scanf的傳回值就是2
  2、如果只有a被成功讀入,傳回值為1
  3、如果a和b都未被成功讀入,傳回值為0
  4、如果遇到錯誤或遇到end of file,傳回值為EOF。
使用scanf函數時應該注意的問題  
       1、sacnf()中的變數必須使用地址。 
  2、scanf()的格式控制串可以使用其它非空白字元,但在輸入時必須輸入這些字元。
  3、在用"%c"輸入時,空格和“逸出字元”均作為有效字元。
  問題一:scanf()函數不能正確接受有空格的字串?如: I love you!

#include <stdio.h>
int main()
{
  char str[80];
  scanf("%s",str);
  printf("%s",str);
  return 0;
}


  輸入:I love you!
  輸出:scanf()函數接收輸入資料時,遇以下情況結束一個資料的輸入:(不是結束該scanf函數,scanf函數僅在每一個資料域均有資料,並按斷行符號後結束)。
  ① 遇空格、“斷行符號”、“跳格”鍵。
  ② 遇寬度結束。
  ③ 遇非法輸入。
  所以,上述程式並不能達到預期目的,scanf()掃描到"I"後面的空格就認為對str的賦值結束,並忽略後面的"love you!".這裡要注意是"love you!"還在鍵盤緩衝區(關於這個問題,網上我所見的說法都是如此,但是,我經過調試發現,其實這時緩衝區字串首尾指標已經相等了,也就是說緩衝區清空了,scanf()輸入一個單詞沒問題,輸入兩個單詞無論加入多少個getchar()都會彈出?

#include <stdio.h>

int main(void)
{
    char name[40];    printf("what's your name?");
    scanf("%s", name);
    printf("%s,hello boy", name);
    getchar();
    getchar();
    return 0;
}

請告訴我是什麼“道理”       scanf讀取時 是遇到空格就停止讀取!也就是說 如果你鍵入得是harry potter 那麼實際上scanf只能擷取harry這個單詞 後面的“ potter”會在停在輸入資料流中那麼你就要最少要加9個getchar(一個空格 6個單詞字母 一個分行符號還有一個待輸入游標)才能看到運行結果       用scanf函數輸入字串時,字串中不能含有空格,否則將以空格作為串的結束符。
       為了避免這種情況,可多設幾個字元數組分段存放含空格的串。        想知道誰在起作用很簡單,因為你輸入幾個單詞的時候,發現只有第一個單詞能夠顯示出來,猜想scanf(%s)提取字元竄的條件是Enter(換行--輸入結束)或者Space(空格),而且還可以做個極端的測試,就你一開始只輸入換行或者空格,發現程式永遠不會執行printf,而只要我們輸入一竄連續字元+一個空格之後,不論我們輸入什麼,Enter之後,printf執行完之後都是一開始的一竄連續字元,因此我們還可以知道,scanf(%s)提取完成的語句格式是一開始遇到的一連竄字元;而由於執行getchar(),之前printf輸出的是scanf所提取的字元竄,而之後的字元或者空格包括斷行符號將會被getchar()調用,其實你的程式兩個getchar()的作用只相當於一個getchar()的作用,因為第一個只不過讀取的是斷行符號符,也就是你輸入一個字元竄之後的斷行符號鍵而已;因此當你輸入幾個用空格隔開的字元竄的時候,無用的getchar()的個數應該等於(斷行符號數)1+n1(空格數)+n2(除第一個連續有形字元竄的其他字元數);所以當你輸入兩個甚至幾個名字的時候,getchar()是遠遠不夠用的; 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.