1. 程式人生 > >使用scanf()函式應注意的問題??

使用scanf()函式應注意的問題??

使用scanf函式時應該注意的問題
  1、sacnf()中的變數必須使用地址。 
  2、scanf()的格式控制串可以使用其它非空白字元,但在輸入時必須輸入這些字元。
  3、在用"%c"輸入時,空格和“轉義字元”均作為有效字元。
  問題一:scanf()函式不能正確接受有空格的字串?如: I love you!
  #include 
  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()函式應該只是掃描stdin流,這個殘存資訊是在stdin中)。我們改動一下上面的程式來驗證一下:
  #include 
  int main()
  {
  char str[80];
  char str1[80];
  char str2[80];
  scanf("%s",str);/*此處輸入:I love you! */
  printf("%s",str);
  sleep(5);/*這裡等待5秒,告訴你程式執行到什麼地方*/
  scanf("%s",str1);/*這兩句無需你再輸入,是對鍵盤盤緩衝區再掃描 */
  scanf("%s",str2);/*這兩句無需你再輸入,是對鍵盤盤緩衝區再掃描 */
  printf("\n%s",str1);
  printf("\n%s",str2);
  return 0;
  }
  輸入:I love you!
  輸出:
  I
  love
  you!
  好了,原因知道了,那麼scanf()函式能不能完成這個任務?回答是:能!別忘了scanf()函式還有一個 %[] 格式控制符(如果對%[]不瞭解的請檢視本文的上篇),請看下面的程式:
  #include "stdio.h"
  int main()
  {
  char string[50];/*scanf("%s",string);不能接收空格符*/
  scanf("%[^\n]",string);
  printf("%s\n",string);
  return 0;
  }
  問題二:鍵盤緩衝區殘餘資訊問題
  #include 
  int main()
  {
  int a;
  char c; do
  {
  scanf("%d",&a);
  scanf("%c",&c);
  printf("a=%d c=%c\n",a,c);/*printf("c=%d\n",c);*/
  }while(c!='N');
  } 
  scanf("%c",&c);這句不能正常接收字元,什麼原因呢?我們用printf("c=%d\n",c);將C用int表示出來,啟用printf("c=%d\n",c);這一句,看看scanf()函式賦給C到底是什麼,結果是c=10 ,ASCII值為10是什麼?換行即\n.對了,我們每擊打一下"Enter"鍵,向鍵盤緩衝區發去一個“回車”(\r),一個“換行"(\n),在這裡\r被scanf()函式處理掉了(姑且這麼認為吧^_^),而\n被scanf()函式“錯誤”地賦給了c.解決辦法:可以在兩個scanf()函式之後加個fflush(stdin);,還有加getch() , getchar()也可以,但是要視具體scanf()語句加那個,這裡就不分析了,讀者自己去摸索吧。但是加fflush(stdin);不管什麼情況都可行。
  (
  函式名: fflush 
  功 能: 清除一個流
  用 法: int fflush(FILE *stream);
  )
  #include 
  int main()
  {
  int a;
  char c; do
  {
  scanf("%d",&a);
  fflush(stdin);
  scanf("%c",&c);
  fflush(stdin);
  printf("a=%d c=%c\n",a,c); }while(c!='N');
  } 
  這裡再給一個用“空格符”來處理緩衝區殘餘資訊的示例:執行出錯的程式:
  #include 
  int main()
  {
  int i;
  char j;
  for(i = 0;i < 10;i++)
  {
  scanf("%c",&j);/*這裡%前沒有空格*/
  }
  }
  使用了空格控制符後:
  #include 
  int main()
  {
  int i;
  char j;
  for(i = 0;i < 10;i++)
  {
  scanf(" %c",&j);/*注意這裡%前有個空格*/
  }
  } 
  可以執行看看兩個程式有什麼不同。
  問題三: 如何處理scanf()函式誤輸入造成程式死鎖或出錯?
  #include 
  int main()
  {
  int a,b,c; /*計算a+b*/
  scanf("%d,%d",&a,&b);
  c=a+b;
  printf("%d+%d=%d",a,b,c);
  }
  如上程式,如果正確輸入a,b的值,那麼沒什麼問題,但是,你不能保證使用者每一次都能正確輸入,一旦輸入了錯誤的型別,你的程式不是死鎖,就是得到一個錯誤的結果,呵呵,這可能所有人都遇到過的問題吧?解決方法:scanf()函式執行成功時的返回值是成功讀取的變數數,也就是說,你這個scanf()函式有幾個變數,如果scanf()函式全部正常讀取,它就返回幾。但這裡還要注意另一個問題,如果輸入了非法資料,鍵盤緩衝區就可能還個有殘餘資訊問題。正確的例程:
  #include 
  int main()
  {
  int a,b,c; /*計算a+b*/
  while(scanf("%d,%d",&a,&b)!=2)fflush(stdin);
  c=a+b;
  printf("%d+%d=%d",a,b,c);
  }
  補充: fflush(stdin)這個方法在GCC下不可用。(在VC6.0下可以)
  以下是 C99 對 fflush 函式的定義:
  int fflush(FILE *stream);
  如果stream指向輸出流或者更新流(update stream),並且這個更新流
  最近執行的操作不是輸入,那麼fflush函式將把任何未被寫入的資料寫入stream
  指向的檔案(如標準輸出檔案stdout)。否則,fflush函式的行為是不確定的。
  fflush(NULL)清空所有輸出流和上面提到的更新流。如果發生寫錯誤,fflush
  函式會給那些流打上錯誤標記,並且返回EOF,否則返回0。
  由此可知,如果 stream 指向輸入流(如 stdin),那麼 fflush 函式的行為是不確定的。故而使用
  fflush(stdin) 是不正確的,至少是移植性不好的。
  可採用如下方法:
  /* 此函式可以和scanf函式一起使用,但使用%c輸入時要注意,即此函式只能用於緩衝區非空的情況 */
  void flush() 
  {
  char c;
  while ((c=getchar()) != '\n'&&c!=EOF) ;
  }
  #include 
  int main()
  {
  int a,b,c; /*計算a+b*/
  while(scanf("%d,%d",&a,&b)!=2) flush();
  c=a+b;
  printf("%d+%d=%d",a,b,c);
  }