scanf 用法及陷阱(轉)


函數名: scanf 
功 能: 執行格式化輸入 
用 法: int scanf(char *format[,argument,...]);
scanf()函數是通用終端格式化輸入函數,它從標准輸入設備(鍵盤) 讀取輸入的信息。可以讀入任何固有類型的數據並自動把數值變換成適當的機內格式。
其調用格式為:      scanf("<格式化字符串>",<地址表>);
scanf()函數返回成功賦值的數據項數,出錯時則返回EOF。
其控制串由三類字符構成:
 
1。格式化說明符; 
2。空白符;
 

3。非空白符
 ;

(A)                格式化說明符

格式字符           說明
%a                 讀入一個浮點值(僅C99有效) 
%A                 同上
%c                 讀入一個字符
%d                 讀入十進制整數
%i                 讀入十進制,八進制,十六進制整數
%o                 讀入八進制整數
%x                 讀入十六進制整數
%X                 同上
%c                 讀入一個字符
%s                 讀入一個
%f                 讀入一個浮點數
%F                 同上
%e                 同上
%E                 同上
%g                 同上
%G                 同上
%p                 讀入一個指針
%u                 讀入一個無符號十進制整數
%n                 至此已讀入值的等價字符數
%[]                掃描字符集合
%%                 讀%符號
  %*                指定類型的數據但不保存
比如:
百分號(%)與格式符之間的星號(*)表示讀指定類型的數據但不保存。因此,
scanf( "%d %*c %d", &x, &y );
 
對 10/20 的讀入操作中,10 放入變量 x,20 放入 y。       
 
       
附加格式說明字符表
修飾符                       說明
L/l 長度修飾符               輸入"長"數據
h 長度修飾符                 輸入"短"數據
W 整型常數                   指定輸入數據所占寬度
* 星號                       空讀一個數據 
hh,ll同上h,l但僅對C99有效。

(B)         空白字符
空白字符會使scanf()函數在讀操作中略去輸入中的一個或多個空白字符,空白符可以是space,tab,newline等等,直到第一個非空白符出現為止。
(C)        非空白字符
一個非空白字符會使scanf()函數在讀入時剔除掉與這個非空白字符相同的字符。 但在輸入時必須輸入這些字符。否則就會出錯 。

注:scanf()控制串知識就介紹到這里(應該比較齊全了^_^),如有遺漏下次補上。下面將結合實際例程,一一闡述.
三、      scanf()函數的控制串的使用
例1.
#include "stdio.h" 
int main(void) 

int a,b,c; 

scanf("%d%d%d",&a,&b,&c); 
printf("%d,%d,%d/n",a,b,c);
return 0;
}  
運行時按如下方式輸入三個值:
3□4□5 ↙(輸入a,b,c的值)
3,4,5 (printf輸出的a,b,c的值)
   (1) &a、&b、&c中的&是地址運算符,分別獲得這三個變量的內存地址。
   (2) "%d%d%d"是按十進值格式輸入三個數值。輸入時,在兩個數據之間可以用一個或多個空格、tab鍵、回車鍵分隔。
      以下是合法輸入方式: 
      ① 3□□4□□□□5↙
      ② 3↙
         4□5↙
      ③ 3(tab鍵)4↙
         5↙

例2.
#include "stdio.h" 
int main(void) 

int a,b,c;
scanf("%d,%d,%d",&a,&b,&c);
printf("%d,%d,%d/n",a,b,c);
return 0;
}  
運行時按如下方式輸入三個值:
3,4,5 ↙(輸入a,b,c的值)
或者
3,□4,□5 ↙(輸入a,b,c的值)
3,□□□4,□5 ↙(輸入a,b,c的值)
......
都是合法的,但是","一定要跟在數字后面,如:
3□,4,□5 ↙就非法了,程序出錯。(解決方法與原因后面講)
再如:
1、sacnf()中的變量必須使用地址。
         int a, b;
scanf("%d%d",a,b); //錯誤
scanf("%d%d",&a,&b);
2、scanf()的格式控制串可以使用其它非空白字符,但在輸入時必須輸入這些字符。
例:
scanf("%d,%d",&a,&b); 
輸入: 3,4 ↙(逗號與"%d,%d"中的逗號對應) 
scanf("a=%d,b=%d",&a,&b); 
輸入: a=3,b=4 ↙("a=","b=",逗號與"%d,%d"中的"a=","b="及逗號對應)

3、在用"%c"輸入時,空格和“轉義字符”均作為有效字符。
例:
scanf("%c%c%c",&c1,&c2,&c3); 
輸入:a□b□c↙ 
結果:a→c1,□→c2,b→c3 (其余被丟棄)

scanf()函數接收輸入數據時,遇以下情況結束一個數據的輸入:(不是結束該scanf函數,scanf函數僅在每一個數據域均有數據,並按回車后結束)。
        ① 遇空格、“回車”、“跳格”鍵。
        ② 遇寬度結束。
        ③ 遇非法輸入。
問題二:scanf()函數不能正確接受有空格的字符串?如: I love you!

#include <stdio.h>
int main()
{
    char str[80];
    
    scanf("%s",str);
    printf("%s",str);
    return 0;
}
輸入:I live you!
輸出:I
       scanf()函數接收輸入數據時,遇以下情況結束一個數據的輸入:(不是結束該scanf函數,scanf函數僅在每一個數據域均有數據,並按回車后結束)。
        ① 遇空格、“回車”、“跳格”鍵。
        ② 遇寬度結束。
        ③ 遇非法輸入。
所以,上述程序並不能達到預期目的,scanf()掃描到"I"后面的空格就認為對str的賦值結束,並忽略后面的"love you!".這里要注意是"love you!"還在鍵盤緩沖區(關於這個問題,網上我所見的說法都是如此,但是,我經過調試發現,其實這時緩沖區字符串首尾指針已經相等了,也就是說緩沖區清 空了,scanf()函數應該只是掃描stdin流,這個殘存信息是在stdin中)。我們改動一下上面的程序來驗證一下:
#include <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
int main()
{
    int i;
    char j;
    for(i = 0;i < 10;i++)
    {
        scanf("%c",&j);/*這里%前沒有空格*/
    }
}
使用了空格控制符后:
#include <stdio.h>
int main()
{
    int i;
    char j;
    for(i = 0;i < 10;i++)
    {
        scanf(" %c",&j);/*注意這里%前有個空格*/
    }
}
    可以運行看看兩個程序有什么不同。
問題四   如何處理scanf()函數誤輸入造成程序死鎖或出錯?
#include <stdio.h>
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 <stdio.h>
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);
}
例如:

#include<stdio.h> 
int main() 

char ch1,ch2; 
printf("Input for ch1:n"); 
scanf("%c",&ch1); 
printf("ch1=%cn",ch1); 
printf("Input for ch2:n"); 
scanf("%c",&ch2); 
printf("ch2=%cn",ch2); 
}

表面上看這段程序是沒有錯的,也可以運行,但運行過程中到 第二個scanf輸入值給ch2時,程序並不會停止下來等待你輸入,而是直接運行到最后一個printf !

為什么?當時百思不得其解。。。

今天上網查了下才知道,原來scanf是從標准輸入緩沖區中讀取輸入的數據,而%c的字符輸入格式會接收回車字符,在輸入第一個scanf時輸入字符后按回車結束,輸入緩沖中保存了這個回車符,遇到第二個scanf時,它自動把這個回車符賦給了ch2 。而如果第二個scanf的輸入格式不是%c時,由於格式不匹配,這個回車符會被自動忽略,所以只有在連續輸入兩個%c的格式時才會出現這樣的問題!

解決辦法:(二辦法任選其一)

1、清空輸入緩沖區

第一個scanf后加入語句:fflush(stdin); //C語言清空輸入緩沖區函數

2、格式控制中加入空格

將第二個scanf改為:scanf(" %c",&ch2);//在%號前面加一個空格

scanf格式輸入時要求輸入格式與格式控制符中的完全一樣(如:scanf("abcd%c",&ch);輸入時必須輸入abcde,ch得到的值為e)空格可以抵消前面輸入的回車符。

 

總結:可見在scanf函數本身是陷阱重重呀,出現下面的情況的時候要格外小心,i

1, 多個scanf函數依次出現的時候

     scanf("%c",&ch1);
     printf("ch1=%cn",ch1);
     printf("Input for ch2:n");
     scanf("%c",&ch2);

2,  當scanf函數輸入字符或者輸入字符串的時候

      scanf("%s",str);

 

3, 當scanf函數的輸入控制格式中 有多個輸入變量的時候

      scanf("%5d %5d %c %c%f%f*f%f",&a,&b,&c1,&c2,&x,&y,&z);

      在這個例子中,就要求如下輸入才有效:5 9 f e 6.888 7.99*f6.886

      當在一個scanf函數中出現多個 %c 即字符輸入的時候 最好用分隔符(空格     )隔開,以避免把一些不想要的空格或回車讀入。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM