摘要:
本文闡述了基于ANSI,Win 95,Win NT上的 C/C++語(yǔ)言中scanf()函數(shù)的用法,以及在實(shí)際使用中常見錯(cuò)誤及對(duì)策。
關(guān)鍵詞:
scanf()
一、 序言
在CSDN論壇的C/C++版塊,我時(shí)常見到“對(duì)于scanf()函數(shù)的用法、及出現(xiàn)的各種錯(cuò)誤而迷惑”的帖子,萌發(fā)了我寫這篇文章的念頭。文中結(jié)合自身在學(xué)習(xí)和編程中對(duì)它的認(rèn)識(shí)和體會(huì),以具體示例闡述問(wèn)題,目的在于使得初學(xué)者能夠正確使用scanf()函數(shù),少走不必要的彎路。
二、 scanf()函數(shù)的用法
scanf()函數(shù)是格式化輸入函數(shù),它從標(biāo)準(zhǔn)輸入設(shè)備(鍵盤) 讀取輸入的信息。
其調(diào)用格式為: scanf("<格式化字符串>",<地址表>);
格式化字符串包括以下三類不同的字符;
1、 格式化說(shuō)明符:
格式化說(shuō)明符與printf()函數(shù)中的格式說(shuō)明符基本相同。但和printf()函數(shù)中格式字符串的用法有一些小區(qū)別。我們來(lái)看下面這個(gè)表。
格式字符 |
說(shuō)明 |
%d |
從鍵盤輸入十進(jìn)制整數(shù) |
%o |
從鍵盤輸入八進(jìn)制整數(shù) |
%x |
從鍵盤輸入十六進(jìn)制整數(shù) |
%c |
從鍵盤輸入一個(gè)字符 |
%s |
從鍵盤輸入一個(gè)字符串 |
%f |
從鍵盤輸入一個(gè)實(shí)數(shù) |
%e |
與%f的作用相同 |
附加格式說(shuō)明字符表
字符 |
說(shuō)明 |
L |
輸入"長(zhǎng)"數(shù)據(jù) |
H |
輸入"短"數(shù)據(jù) |
M |
指定輸入數(shù)據(jù)所占寬度 |
* |
空讀一個(gè)數(shù)據(jù) |
2、 空白字符: 空白字符會(huì)使scanf()函數(shù)在讀操作中略去輸入中的一個(gè)或多個(gè)空白字符。
3、 非空白字符: 一個(gè)非空白字符會(huì)使scanf()函數(shù)在讀入時(shí)剔除掉與這個(gè)非空白字符相同的字符。
地址表是需要讀入的所有變量的地址,而不是變量本身。這與printf()函數(shù)完全不同,要特別注意。各個(gè)變量的地址之間同","分開。
例如:
#include <stdio.h>
void main()
{
int i, j;
printf("i, j=?\n");
scanf("%d, %d", &i, &j);
}
上例中的scanf()函數(shù)先讀一個(gè)整型數(shù),然后把接著輸入的逗號(hào)剔除掉,最后讀入另一個(gè)整型數(shù)。如果","這一特定字符沒(méi)有找到,scanf()函數(shù)就終止。若參數(shù)之間的分隔符為空格,則參數(shù)之間必須輸入一個(gè)或多個(gè)空格。
說(shuō)明:
(1) 對(duì)于字符串?dāng)?shù)組或字符串指針變量,由于數(shù)組名和指針變量名本身就是地址,因此使用scanf()函數(shù)時(shí),不需要在它們前面加上"&"操作符。
例如:
#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);
}
(2) 可以在格式化字符串中的"%"各格式化規(guī)定符之間加入一個(gè)整數(shù),表示任何讀操作中的最大位數(shù)。
如上例中若規(guī)定只能輸入10字符給字符串指針p,則第一條scanf() 函數(shù)語(yǔ)句變?yōu)椋?/SPAN>scanf("%10s", p);
程序運(yùn)行時(shí)一旦輸入字符個(gè)數(shù)大于10,p就不再繼續(xù)讀入,而后面的一個(gè)讀入函數(shù)即scanf("%s", str)就會(huì)從第11個(gè)字符開始讀入。
(3) scanf()函數(shù)中沒(méi)有精度控制。
如: scanf("%5.2f",&a); 是非法的。不能企圖用此語(yǔ)句輸入小數(shù)為2位的實(shí)數(shù)。
(4) scanf中要求給出變量地址,如給出變量名則會(huì)出錯(cuò)
如 scanf("%d",a);是非法的,應(yīng)改為scnaf("%d",&a);才是合法的。
(5) 在輸入多個(gè)數(shù)值數(shù)據(jù)時(shí),若格式控制串中沒(méi)有非格式字符作輸入數(shù)據(jù)之間的間隔則可用空格,TAB或回車作間隔。
C編譯在碰到空格,TAB,回車或非法數(shù)據(jù)(如對(duì)“%d”輸入“12A”時(shí),A即為非法數(shù)據(jù))時(shí)即認(rèn)為該數(shù)據(jù)結(jié)束。
(6) 在輸入字符數(shù)據(jù)(%c)時(shí),若格式控制串中無(wú)非格式字符,則認(rèn)為所有輸入的字符均為有效字符。
例如:scanf("%c%c%c",&a,&b,&c);
輸入為:
d e f
則把'd'賦予a, ' (空格)'賦予b,'e'賦予c。因?yàn)?/SPAN>%c 只要求讀入一個(gè)字符,后面不需要用空格作為兩個(gè)字符的間隔,因此把' '作為下一個(gè)字符送給b。
只有當(dāng)輸入為:def 時(shí),才能把'd'賦于a,'e'賦予b,'f'賦予c。 如果在格式控制中加入空格作為間隔,
如 scanf ("%c %c %c",&a,&b,&c);則輸入時(shí)各數(shù)據(jù)之間可加空格。
我們用一些例子來(lái)說(shuō)明一些規(guī)則:
#include <stdio.h>
void main()
{
char a,b;
printf("input character a,b\n");
scanf("%c%c",&a,&b); /*注意兩個(gè)%c之間沒(méi)有任何符號(hào)*/
printf("%c%c\n",a,b);
}
由于scanf函數(shù)"%c%c"中沒(méi)有空格,輸入M N,結(jié)果輸出只有M。而輸入改為MN時(shí)則可輸出MN兩字符,見下面的輸入運(yùn)行情況: 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); /*注意兩個(gè)%c之間有個(gè)空格*/
printf("\n%c%c\n",a,b);
}本例表示scanf格式控制串"%c %c"之間有空格時(shí), 輸入的數(shù)據(jù)之間可以有空格間隔。
(7) 如果格式控制串中有非格式字符則輸入時(shí)也要輸入該非格式字符。
例如:
scanf("%d,%d,%d",&a,&b,&c); 其中用非格式符“ , ”作間隔符,故輸入時(shí)應(yīng)為: 5,6,7 (與scanf 雙引號(hào)之間的格式必須一樣)
又如: scanf("a=%d,b=%d,c=%d",&a,&b,&c);
則輸入應(yīng)為 a=5,b=6,c=7
如輸入的數(shù)據(jù)與輸出的類型不一致時(shí),雖然編譯能夠通過(guò),但結(jié)果將不正確。
#include <stdio.h>
void main()
{
int a;
printf("input a number");
scanf("%d",&a);
printf("%ld",a);
}
由于輸入數(shù)據(jù)類型為整型, 而輸出語(yǔ)句的格式串中說(shuō)明為長(zhǎng)整型,因此輸出結(jié)果和輸入數(shù)據(jù)不符。輸出并不是輸入的值。
如將Scanf("%d",&a); 語(yǔ)句改為 scanf("%ld",&a);
輸入數(shù)據(jù)為長(zhǎng)整型,輸入輸出數(shù)據(jù)才相等。
三、 常見錯(cuò)誤及對(duì)策
問(wèn)題1:
我初學(xué)C程序,所以提的問(wèn)題很淺,希望您不要見笑。我自己編了一個(gè)程序,但運(yùn)行的結(jié)果與我預(yù)期的不一樣。
#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);
則程序運(yùn)行結(jié)果變成
please input num:i=1 j=2
num=6
num=6(我原本希望能重復(fù)第一行再讓我輸入)
Programm is complete.
為什么第二次不能輸入?
答復(fù):
我使用Turbo C 2.0證實(shí)存在你說(shuō)的問(wèn)題。象scanf("i=%d j=%d",&i,&j);這樣的輸入方式比較特別,TC 2.0顯然在第一次輸入后沒(méi)有象正常情況一樣清楚輸入緩沖區(qū),這樣第二次執(zhí)行scanf時(shí),程序并沒(méi)有讓你輸入而是直接讀入上次輸入的結(jié)果。如果你一定要這么做,應(yīng)該在scanf之前加上:
fflush(stdin);
這樣清楚掉鍵盤緩沖區(qū)。
問(wèn)題2:
為什么要把scanf("%c",varname)一定改成scanf(" %c")才可以正確接收字符?
答復(fù):
類似上題,在%c的前面必須有一個(gè)空格,否則系統(tǒng)會(huì)將你前面輸入別的值之后鍵入的回車符讀入該變量,造成死循環(huán)。當(dāng)然,如果scanf("%c",&varname)是第一條讀入語(yǔ)句,就可以不需要空格。
問(wèn)題3:(輸入變量時(shí)忘記加地址運(yùn)算符“&”)
int a,b;
scanf("%d%d",a,b);
答復(fù):
這是不合法的。Scanf函數(shù)的作用是:按照a、b在內(nèi)存的地址將a、b的值存進(jìn)去。“&a”指a在內(nèi)存中的地址。
問(wèn)題4:(輸入數(shù)據(jù)的方式與要求不符)
①scanf("%d%d",&a,&b);
輸入時(shí),不能用逗號(hào)作兩個(gè)數(shù)據(jù)間的分隔符,如下面輸入不合法:
3,4
輸入數(shù)據(jù)時(shí),在兩個(gè)數(shù)據(jù)之間以一個(gè)或多個(gè)空格間隔,也可用回車鍵,跳格鍵tab。
②scanf("%d,%d",&a,&b);
C規(guī)定:如果在“格式控制”字符串中除了格式說(shuō)明以外還有其它字符,則在輸入數(shù)據(jù)時(shí)應(yīng)輸入與這些字符相同的字符。下面輸入是合法的:
3,4
此時(shí)不用逗號(hào)而用空格或其它字符是不對(duì)的。
3 4 3:4
又如:
scanf("a=%d,b=%d",&a,&b);
輸入應(yīng)如以下形式:
a=3,b=4
問(wèn)題5:(輸入字符的格式與要求不一致)
在用“%c”格式輸入字符時(shí),“空格字符”和“轉(zhuǎn)義字符”都作為有效字符輸入。
scanf("%c%c%c",&c1,&c2,&c3);
如輸入a b c
字符“a”送給c1,字符“ ”送給c2,字符“b”送給c3,因?yàn)?/SPAN>%c只要求讀入一個(gè)字符,后面不需要用空格作為兩個(gè)字符的間隔。
問(wèn)題6:(.輸入輸出的數(shù)據(jù)類型與所用格式說(shuō)明符不一致)
例如,a已定義為整型,b定義為實(shí)型
a=3;b=4.5;
printf("%f%d\n",a,b);
編譯時(shí)不給出出錯(cuò)信息,但運(yùn)行結(jié)果將與原意不符。這種錯(cuò)誤尤其需要注意。
問(wèn)題7:(輸入數(shù)據(jù)時(shí),企圖規(guī)定精度)
scanf("%7.2f",&a);
這樣做是不合法的,輸入數(shù)據(jù)時(shí)不能規(guī)定精度。
問(wèn)題8:(在不應(yīng)加地址運(yùn)算符&的位置加了地址運(yùn)算符)
scanf("%s",&str);
C語(yǔ)言編譯系統(tǒng)對(duì)數(shù)組名的處理是:數(shù)組名代表該數(shù)組的起始地址,且scanf函數(shù)中的輸入項(xiàng)是字符數(shù)組名,不必要再加地址符&。應(yīng)改為:scanf("%s",str);
四、 結(jié)論
本文主要講述了C/C++中的scanf()函數(shù)的用法,重點(diǎn)闡述使用scanf()函數(shù)過(guò)程中出現(xiàn)的常見錯(cuò)誤及對(duì)策。當(dāng)然,文中某些解決方法,均可以采用其他函數(shù)和方法來(lái)更好地解決,但本文僅限討論scanf()函數(shù)本身。文中難免存在一些不足之處,歡迎讀者批評(píng)指正。