使用scanf()函式應注意的問題??
阿新 • • 發佈:2019-02-06
使用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);
}
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);
}