關於scanf()函數

最近在網上看到幾篇關於scanf函數的文章,與大家分享一下!

 

scanf()函數探討(1)——使用說明<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


函數scanf()是從標準輸入流stdin中讀內容的通用子程序,可以讀入全部固有類型的數據並自動轉換成機內形式。
    format
指向的控制串由以下三類字符組成:
       ●
格式說明符
       ●
空白符
       ●
非空白符

     轉換字符(就是%後跟的部分)   
       a  
讀浮點值(僅適用於
C99)         
       A  
讀浮點值(僅適
C99)             
       c  
讀單字符
                        
       d  
讀十進制整數
                     
       i  
讀十進制、八進制、十六進制整數
   
       e  
讀浮點數
                         
       E  
讀浮點數
                         
       f  
讀浮點數
                          
       F  
讀浮點數(僅適用於
C99)        
       g  
讀浮點數
                    
       G  
讀浮點數
                     
       o  
讀八進制數
                  
       s  
讀字符串
                   
       x  
讀十六進制數
               
       X  
讀十六進制數
               
       p  
讀指針值
                    
       n  
至此已讀入值的等價字符數
      
       u  
讀無符號十進制整數
           
      [ ]
掃描字符集合
                
       *  
空讀一個數據
              
       %  
% 符號(百分號)            

(1)例如: %s 表示讀串而 %d 表示讀整數。格式串的處理順序爲從左到右,格式說明符逐一與變元表中的變元匹配。爲了讀取長整數,可以將 l(ell) 放在格式說明符的前面;爲了讀取短整數,可以將 h 放在格式說明符的前面。這些修飾符可以與 diou x 格式代碼一起使用。

(2)默認情況下,afe g 告訴 scanf() float 分配數據。 如果將 l(ell) 放在這些修飾符的前面,則 scanf() double 分配數據。使用 L 就是告訴 scanf(),接收數據的變量是 long double 型變量。

    (3)控制串中的空白符使 scanf() 在輸入流中跳過一個或多個空白行。空白符可以是空格(space)、製表符(tab)和新行符(newline)。本質上,控制串中的空白符使 scanf() 在輸入流中讀,但不保存結果,直到發現非空白字符爲止。

    (4)非空白符使 scanf() 在流中讀一個匹配的字符並忽略之。例如,"%d,%d" 使 scanf() 先讀入一個整數,讀入中放棄逗號,然後讀另一個整數。如未發現匹配,scanf() 返回。

    (5)scanf() 中用於保存讀入值的變元必須都是變量指針,即相應變量的地址。

    (6)在輸入流中,數據項必須由空格、製表符和新行符分割。逗號和分號等不是分隔符,比如以下代碼:scanf( "%d %d", &r, &c );將接受輸入 10 20,但遇到 10,20 則失敗。

    (7)百分號(%)與格式符之間的星號(*)表示讀指定類型的數據但不保存。因此,
scanf( "%d %*c %d", &x, &y );
10/20 的讀入操作中,10 放入變量 x20 放入 y

(8)格式命令可以說明最大域寬。 在百分號(%)與格式碼之間的整數用於限制從對應域讀入的最大字符數。例如,希望向 address 讀入不多於 20 個字符時,可以書寫成如下形式:
    (9)scanf( "%20s", address );
如果輸入流的內容多於 20 個字符,則下次 scanf() 從此次停止處開始讀入。 若達到最大域寬前已遇到空白符,則對該域的讀立即停止;此時,scanf() 跳到下一個域。

 (10)雖然空格、製表符和新行符都用做域分割符號,但讀單字符操作中卻按一般字符處理。例如,對輸入流 "x y" 調用:
    scanf( "%c%c%c", &a, &b, &c );
返回後,x 在變量 a 中,空格在變量 b 中,y 在變量 c 中。

    (12)注意,控制串中的其它字符,包括空格、製表符和新行符,都用於從輸入流中匹配並放棄字符,被匹配的字符都放棄。例如,給定輸入流 "10t20",調用:
    scanf( "%dt%d", &x, &y );
將把 10 20 分別放到 x y 中,t 被放棄,因爲 t 在控制串中。

    (13)ANSI C 標準向 scanf() 增加了一種新特性,稱爲掃描集(scanset)。 掃描集定義一個字符集合,可由 scanf() 讀入其中允許的字符並賦給對應字符數組。掃描集合由一對方括號中的一串字符定義,左方括號前必須綴以百分號。 例如,以下的掃描集使 scanf() 讀入字符 AB C%[ABC]    使用掃描集時,scanf() 連續喫進集合中的字符並放入對應的字符數組,直到發現不在集合中的字符爲止(即掃描集僅讀匹配的字符)。返回時,數組中放置以 null 結尾、由讀入字符組成的字符串。用字符 ^ 可以說明補集。把 ^ 字符放爲掃描集的第一字符時,構成其它字符組成的命令的補集合,指示 scanf() 只接受未說明的其它字符。對於許多實現來說,用連字符可以說明一個範圍。例如,以下掃描集使 scanf() 接受字母 A Z %[A-Z]  重要的是要注意掃描集是區分大小寫的。因此,希望掃描大、小寫字符時,應該分別說明大、小寫字母。
   
  
(14)scanf()
返回等於成功賦值的域數的值,但由於星號修飾符而讀入未賦值的域不計算在內。給第一個域賦值前已出錯時,返回 EOF

   

 

 

 

 

scanf()函數探討(2)——使用說明

(15)對於字符串數組或字符串指針變量,由於數組名和指針變量名本身就是地址,因此使用scanf()函數時,不需要在它們前面加上"&"操作符。

例如:

#include <stdio.h>

void main()

{

       char *p, str[20];

        p = new char[20];  

        scanf("%s", p); /*從健盤輸入字符串*/

        scanf("%s", str);

        printf("%s/n", p); /*向屏幕輸出字符串*/

        printf("%s/n", str);

}

(16)可以在格式化字符串中的"%"各格式化規定符之間加入一個整數,表示任何讀操作中的最大位數。如上例中若規定只能輸入10字符給字符串指針p,則第一條scanf() 函數語句變爲:scanf("%10s", p);

程序運行時一旦輸入字符個數大於10p就不再繼續讀入,而後面的一個讀入函數即scanf("%s", str)就會從第11個字符開始讀入。

(17) scanf()函數中沒有精度控制。

如: scanf("%5.2f",&a); 是非法的。不能企圖用此語句輸入小數爲2位的實數。

18scanf中要求給出變量地址,如給出變量名則會出錯

scanf("%d",a);是非法的,應改爲scnaf("%d",&a);纔是合法的。

19)在輸入多個數值數據時,若格式控制串中沒有非格式字符作輸入數據之間的間隔則可用空格,TAB或回車作間隔。C編譯在碰到空格,TAB,回車或非法數據(如對“%d”輸入“12A”時,A即爲非法數據)時即認爲該數據結束。

20)在輸入字符數據(%c)時,若格式控制串中無非格式字符,則認爲所有輸入的字符均爲有效字符。

例如:scanf("%c%c%c",&a,&b,&c);

輸入爲:

d e f

則把'd'賦予a, ' (空格)'賦予b,'e'賦予c。因爲%c 只要求讀入一個字符,後面不需要用空格作爲兩個字符的間隔,因此把' '作爲下一個字符送給b。只有當輸入爲:def 時,才能把'd'賦於a,'e'賦予b,'f'賦予c。 如果在格式控制中加入空格作爲間隔,

scanf ("%c %c %c",&a,&b,&c);則輸入時各數據之間可加空格。

我們用一些例子來說明一些規則:

#include <stdio.h>

void main()

{

       char a,b;

       printf("input character a,b/n");

       scanf("%c%c",&a,&b);   /*注意兩個%c之間沒有任何符號*/

       printf("%c%c/n",a,b);

}

由於scanf函數"%c%c"中沒有空格,輸入M N,結果輸出只有M。而輸入改爲MN時則可輸出MN兩字符,見下面的輸入運行情況: input character a,b

MN     (你輸入的值)

MN     (屏幕上顯示的值)

#include <stdio.h>

void main()

{

       char a,b;

       printf("input character a,b/n");

       scanf("%c %c",&a,&b); /*注意兩個%c之間有個空格*/

       printf("/n%c%c/n",a,b);

}

本例表示scanf格式控制串"%c %c"之間有空格時, 輸入的數據之間可以有空格間隔。

21)如果格式控制串中有非格式字符則輸入時也要輸入該非格式字符。

例如:

scanf("%d,%d,%d",&a,&b,&c); 其中用非格式符“ , ”作間隔符,故輸入時應爲: 5,6,7 (scanf 雙引號之間的格式必須一樣)

又如: scanf("a=%d,b=%d,c=%d",&a,&b,&c);

則輸入應爲 a=5,b=6,c=7

如輸入的數據與輸出的類型不一致時,雖然編譯能夠通過,但結果將不正確。

#include <stdio.h>

void main()

{

       int a;

       printf("input a number");

       scanf("%d",&a);

       printf("%ld",a);

}

由於輸入數據類型爲整型,而輸出語句的格式串中說明爲長整型,因此輸出結果和輸入數據不符。輸出並不是輸入的值。如將Scanf("%d",&a); 語句改爲 scanf("%ld",&a);

輸入數據爲長整型,輸入輸出數據才相等。

 

 

 

 

 

 

 

 

 

 

 

 

scanf()函數探討(3)——常見錯誤和解答

1.空白符問題

#include<stdio.h>
main()
{  
   int a;
   printf("input the data/n");
   scanf("%d/n",&a);//
這裏多了一個回車符/n
   printf("%d",a);
   return 0;
}

結果要輸入兩個數程序才結束,而不是預期的一個。
原因:用空白符結尾時,scanf會跳過空白符去讀下一個字符,所以你必須再輸入一個數。這裏的空白符包括空格,製表符,換行符,回車符和換頁符。所以如果你用scanf("%d ",&a)也會出現同樣的問題。
解決方法:這種錯誤大多是輸入的時候不小心,多注意一點就好了。這種問題也不好檢查,編譯沒有問題,一個空格也不容易看出來。當你的程序出現上面的問題時,自己對照檢查一下就可以了。

2.緩衝區問題
這是一個非常容易錯的地方。

#include <stdio.h>
main()
{
int n = 5;
char c[n];
for(int i = 0; i < n; i++)
   c[i] = scanf("%c",&c[i]);
printf(c);
   return 0;
}


如果輸入:
a
b
c
那麼循環就會提前結束了
.
原因:輸入a和第一個回車後,a和這個回車符都留在緩衝區中。第一個scanf讀取了a,但是輸入緩衝區裏面還留有一個/n,第二個scanf讀取這個/n。然後輸入b和第二個回車,同樣的,第三個scanf讀取了b,第四個scanf讀取了第二個回車符。第五個讀取了c。所以五個scanf都執行了,並沒有提前結束。只不過有的scanf讀取到了回車符而已。
解決方法:把程序改成這樣就可以了:

for( i = 0; i < n; i++){
   scanf("%c",&c[i]);
fflush(stdin);//
刷新緩衝區
}

或者不用scanf,而用gets()函數,如:

#include<stdio.h>
main()
{  
   char c[5];
   gets(c);
   printf(c);
   return 0;
}

但要注意:這個函數自動把你最後敲的回車轉換爲字符'/0'。如果你的輸入超過了數組的大小,那麼就會產生錯誤。


3.scanf()函數的參數輸入類型不匹配問題
這是我在csdn論壇上見到的問題,這個錯誤有時候會讓人莫名其妙。

#include<stdio.h>
main()
{
int a=123;
char c='t';
printf("input/n");
scanf("%d%c",&a,&c);
scanf("%d%c",&a,&c);
scanf("%d%c",&a,&c);
printf("%d/n%c/n",a,c);
return 0;
}

當輸入a 回車 後,會直接跳過下面2個scanf語句,直接輸出爲
123
t
原因:對於scanf("%d%c",&a,&c)scanf語句執行時,首先試圖從緩衝區中讀入一個%d類型的數據,如果和第一個參數匹配,則繼續從緩衝區中讀取數據和第二個參數進行匹配,依次進行下去,直到匹配完所有的參數;如果其中有一個參數不匹配,那就從這個地方跳出,忽略這個 scanf後面所有的參數,而去執行下一條語句。
可以用下面的程序驗證一下:

#include <stdio.h>
int main()
{
int a=123,b=1;
char c='t';
   scanf("%d%d",&a,&b);
scanf("%c",&c);
printf("%d/n%d/n%c/n",a,b,c);
return 0;
}

輸入:2 回車a 回車
結果是:
2
1
a
解決方法scanf()函數執行成功時的返回值是成功讀取的變量數,也就是說,你這個scanf()函數有幾個變量,如果scanf()函數全部正常讀取,它就返回幾。但這裏還要注意另一個問題,如果輸入了非法數據,鍵盤緩衝區就可能還個有殘餘信息問題。
比如:

#include <stdio.h>
main()
{
int a=123,b;
while(scanf("%d%d",&a,&b)!=2)
   fflush(stdin);
printf("%d/n%d/n",a,b);
return 0;
}

你可以試一下,如果輸入不是數字時,會有什麼反應。

補充scanf中一種很少見但很有用的轉換字符:[...][ ^...]

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


運行,輸入:1234werew後,結果是:1234。通過運行可以發現它的作用是:如果輸入的字符屬於方括號內字符串中某個字符,那麼就提取該字符;如果一經發現不屬於就結束提取。該方法會自動加上一個字符串結束符到已經提取的字符後面。
    scanf("%[^1234567890]",strings);
它的作用是:如果一經發現輸入的字符屬於方括號內字符串中某個字符,那麼就結束提取;如果不屬於就提取該字符。該方法會自動加上一個字符串結束符到已經提取的字符後面。

   
注意:方括號兩邊不能空格,如:scanf("%[ 1234567890 ]",strings); scanf("%[ ^1234567890 ]",strings); 不讓空格也會算在裏面的。用這種方法還可以解決scanf的輸入中不能有空格的問題。只要用scanf("%[^/n]",strings); 就可以了。很神奇吧。

4.一些問題
問題1

#include<stdio.h>

void   main()

{

       static int a[2][3]={{1,3,4},{7,9,6}};

       int i,j,k;

       for(k=1;k<=2;k++)

       {printf("Please input num:");

       scanf("%d %d",&i,&j);

       if(i<2&&j<3)

               printf("num=%d/n",a[i][j]);

       else printf("Input is error,/n");

       }

       printf("programm is complete./n");

}

如果將第8行改爲

scanf("i=%d j=%d",&i,&j);

則程序運行結果變成

please input num:i=1 j=2

num=6

Programm is complete. (原本希望能重複第一行再讓我輸入)

爲什麼第二次不能輸入?

解答:象scanf("i=%d j=%d",&i,&j);這樣的輸入方式比較特別,顯然在第一次輸入後沒有象正常情況一樣清楚輸入緩衝區,這樣第二次執行scanf時,程序並沒有讓你輸入而是直接讀入上次輸入的結果。如果你一定要 這麼做,應該在scanf之前加上: fflush(stdin);

這樣清楚掉鍵盤緩衝區。



問題2

爲什麼要把scanf("%c",varname)一定改成scanf(" %c")纔可以正確接收字符?

答覆:

類似上題,在%c的前面必須有一個空格,否則系統會將你前面輸入別的值之後鍵入的回車符讀入該變量,造成死循環。當然,如果scanf("%c",&varname)是第一條讀入語句,就可以不需要空格。


問題3:(輸入字符的格式與要求不一致)

在用“%c”格式輸入字符時,空格字符轉義字符都作爲有效字符輸入。

scanf("%c%c%c",&c1,&c2,&c3);

如輸入a b c

字符“a”送給c1,字符“ ”送給c2,字符“b”送給c3,因爲%c只要求讀入一個字符,後面不需要用空格作爲兩個字符的間隔。


問題4:(輸入輸出的數據類型與所用格式說明符不一致)

例如,a已定義爲整型,b定義爲實型

a=3;b=4.5;

printf("%f%d/n",a,b);

編譯時不給出出錯信息,但運行結果將與原意不符。這種錯誤尤其需要注意。


問題5:(輸入數據時,企圖規定精度)

scanf("%7.2f",&a);

這樣做是不合法的,輸入數據時不能規定精度。


問題6:(在不應加地址運算符&的位置加了地址運算符)

scanf("%s",&str);

C語言編譯系統對數組名的處理是:數組名代表該數組的起始地址,且scanf函數中的輸入項是字符數組名,不必要再加地址符&。應改爲:scanf("%s",str);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章