你首先要明白,從鍵盤讀入鍵盤緩沖區(qū)(buffer)的數(shù)據(jù)都是以ASCII碼存儲的(包括回車)。
成都創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比甘南網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式甘南網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋甘南地區(qū)。費(fèi)用合理售后完善,10多年實(shí)體公司更值得信賴。
程序1
#include "stdio.h"
void main()
{
char a;
char b;
scanf("%d",a);
scanf("%d",b);
printf("%d %d",a,b);
}
鍵盤輸入
97回車
第一次回車后,buffer中的ASCII:39h,37h,0AH(0A是換行的ASCII), scanf會根據(jù)格式字符串中的第一個%d對buffer按字節(jié)順序讀取,當(dāng)讀取到0A時,認(rèn)為%d型的數(shù)據(jù)結(jié)束,此時把已經(jīng)讀取到的39h,37h依據(jù)%d轉(zhuǎn)為整型數(shù)據(jù)97存儲在字符型變量a中。(這里是除去了掃描截止點(diǎn)0AH)
此時buffer中已經(jīng)無任何數(shù)據(jù)了。
96回車
第二次回車后,按同樣的流程,scanf會根據(jù)格式字符串中的第二個%d對buffer按字節(jié)順序讀取。最終b得到96.
此時buffer中已經(jīng)無任何數(shù)據(jù)了。
輸出
97 96
程序2
#include "stdio.h"
void main()
{
char a;
char b;
scanf("%c",a);
scanf("%c",b);
printf("%d %d",a,b);
}
鍵盤輸入
9回車buffer:39H,0AH
因?yàn)閟canf會按照第一個%c格式掃描buffer(只掃描一個字節(jié)就結(jié)束),然后把掃描到的39H直接送到變量a(當(dāng)以%d格式讀出來時,39H就是57)
此時,buffer中只有:0AH。
然后,scanft又遇到第二個%c,繼續(xù)掃描buffer,得到0aH并送入變量b.
此時buffer中已經(jīng)無任何數(shù)據(jù)了
輸出
57 10
程序3
#include "stdio.h"
void main()
{
char a[100];
char b[100];
scanf("%s",a);
scanf("%s",b);
printf("%s %s",a,b);
}
鍵盤輸入
abc回車
第一次回車后,buffer:61H,62H,63H,0AH。
scanf會按照%s的格式對buffer按字節(jié)順序掃描,當(dāng)掃描到0AH時,結(jié)束掃描(按照%s的要求,空格20H也是掃描結(jié)束點(diǎn))。
然后把掃描到的(除去最后一個判斷掃描截至的字節(jié)0AH)數(shù)據(jù)直接送入以a為起始地址的字符串。
此時,buffer無任何數(shù)據(jù)了。
def回車
第二次回車后,buffer:65H,66H,67H,0AH.掃描的流程與上面的完全一致。
輸出
abc def
程序4
#include stdio.h
void main()
{
int i;
char j;
for(i=0;i2;i++)
scanf("%c",j);/*注意這里%前沒有空格*/
printf("%d",j);
}
鍵盤輸入
1回車,
這里scanf執(zhí)行了兩次(i==0時,與i==1時),而且每次都是想對j賦值。
第一次scanf,按%c的要求,只掃描buffer中的一個字節(jié),但是buffer中并不數(shù)據(jù),于是要求鍵盤輸入數(shù)據(jù)到buffer,此時的1回車代表向buffer中輸入了:31H,0AH。
然后按%c的要求,只掃描buffer中的一個字節(jié):31h,并將它直接送入變量j.
此時,buffer中還留下:0AH。
第二次scanf要求鍵盤輸入數(shù)據(jù),按%c的要求,只掃描buffer中的一個字節(jié):0Ah,并將它直接送入變量j.
此時,buffer無數(shù)據(jù)了。
最后,你用%d格式輸出j的值(0AH換成整型就是10)
輸出
10
程序5
#include stdio.h
void main()
{
int i;
char j;
for(i=0;i2;i++)
scanf(" %c",j);/*注意這里%前有一個空格*/
printf("%d",j);
}
1回車2enter的情況:
scanf會按照格式控制字符串的要求,順序掃描buffer.
但是你其中有一個空格,這個很特殊,我也是第一次發(fā)現(xiàn)這個問題(一般我都不會在scanf中加入任何常量字符)
我測試了一下:我發(fā)現(xiàn)這個空格有吸收回車(0AH)和空格(20H)的“神奇功效”,吸收之后再要求buffer給一個字節(jié),直到這個字節(jié)不是0AH或者 20H,此時把這個字節(jié)交給下一個格式字串。
第一次循環(huán)時遇到格式字串空格,就掃描buffer中的一個字節(jié),但是buffer中無數(shù)據(jù),要求從鍵盤輸入數(shù)據(jù):1〈回車〉,buffer中有數(shù)據(jù)了——31H,0AH。再讀取到字節(jié)31H,scanf發(fā)現(xiàn)這個并不是0AH/20H,就把這個字節(jié)31H交給格式字符%c處理。
循環(huán)結(jié)束,此時buffer里面還有:0AH.
第二次循環(huán)時遇到格式字串空格,就掃描buffer中的一個字節(jié)——0AH,發(fā)現(xiàn)是0AH/20H,于是就要求buffer再來一個字節(jié)。此時buffer里面已經(jīng)沒有數(shù)據(jù)了,要求鍵盤輸入:2enter.
buffer中有數(shù)據(jù)了——32H,0AH。于是再讀一個字節(jié)31H,scanf發(fā)現(xiàn)這個并不是0AH/20H,就把這個字節(jié)32H交給格式字符%c處理(j最終得到32H)。
循環(huán)結(jié)束,此時buffer里面還有:0AH.
這里有一篇關(guān)于Printf的帖子:
程序6
#include "stdio.h"
void main()
{
int a;
int b;
scanf("%c",a);
scanf("%c",b);
printf("%d %d",a,b);
}
鍵盤輸入
1回車
問題5:
你的編譯器VC認(rèn)為%d數(shù)據(jù)應(yīng)該是4個字節(jié),但是你采用的是%c讀數(shù)據(jù),
scanf("%c",a);此句讀到的是1的ascii碼:31h.然后把31H直接送入地址a(而并沒有改寫a的三個高字節(jié)地址)。
scanf("%c",b);同理。
你可以用printf("a=%x,b=%x\n",a,b);來驗(yàn)證我說的。它們的最低字節(jié)肯定是31H,0AH。
PS1:
當(dāng)你把 int a;int b;放在main()外進(jìn)行定義時,a,b的初值就是0。此時你會得到正確的結(jié)果。
當(dāng)你把 int a;int b;放在main()內(nèi)進(jìn)行定義時,a,b不會被初始化(它們的三個三個高字節(jié)地址的內(nèi)容是不確定的),你就會得到上面錯誤的結(jié)果。(定義的動態(tài)變量都不會被初始化,靜態(tài)變量會被初始化為0)
PS2:以下也是不正確的用法。
char c;
scanf("%d",c);/當(dāng)你用%d給c賦值時,會對從&c開始的連續(xù)4個字節(jié)進(jìn)行賦值。當(dāng)從buffer得到的值是在一個字節(jié)范圍內(nèi)(-128~127),下面是可以正常輸出的。但是不管怎樣,這樣做是很危險的——越界。
printf("%d",c);
=================請你測試下這個程序========================
#include "stdio.h"
void main()
{
char c[4],i=4;
scanf("%d",c);/*請輸入258回車*/
while(i--0)
printf("%02x ",c[i]);
printf("\n");
}/*如果得到的結(jié)果是00 00 00 01 02就說明我的結(jié)論是正確的(258的轉(zhuǎn)為16進(jìn)制數(shù)就是00 00 01 02H,然后scanf會把這個數(shù)放入以c為起始地址的)
================以下程序也是======================
#include "stdio.h"
void main()
{
char c,i=4;
char *p=c;
scanf("%d",c);/*請輸入258回車*/
while(i--0)
printf("%02x ",p[i]);
printf("\n");
}
關(guān)于清空緩沖區(qū),舉例如下:
#includestdio.h
int?main()
{
int?x;
scanf("%d",?x);
fflush(stdin);??//清空輸入緩沖
scanf("%d",x);//清空緩沖區(qū)后繼續(xù)輸入
printf("%d\n",x);
return?0;
}
%d后面的空格是用來匹配所有的連續(xù)空白字符的(空白字符包括空格 \t \n)直到碰到不是空白的字符。
這個用法主要是為了匹配輸入時的空白符,舉個例子:
int?a;
char?c;
scanf("%d",a);
scanf("%c",c);
上面這個輸入代碼里,如果是分兩次輸入(用空白分割),那么c是沒有機(jī)會輸入的,尤其是從文件讀取的時候,會有很多的空白符,c會讀取到緩沖區(qū)的空白,一般解決這個問題是再用一句gtechar(), ,但如果有很多空白就比較麻煩(文件里這種情況很多),如果在%d后面加個空格,就可以吧剩下所有的空白符給吸收掉:
int?a;
char?c;
scanf("%d?",a);?//這樣可以把空白吸收掉
scanf("%c",c);
在你這個代碼里,輸入全是%d格式,那這個空格就沒必要了,不如去掉