前言
今天看到博友發了個有關scanf
的使用的注意事項,就是討論緩衝區殘存資料的問題,用簡單的程式碼示例複述一下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int a;
char b;
scanf("%d", &a);
scanf("%c", &b);
printf("a = %d , b = %d\n", a, b);
system("pause");
return 0;
}
你或許碰到這個輸出:
5
a = 5 , b = 10
請按任意鍵繼續. . .
我明明想輸入個5,然後回車輸入下一個字元,但是,回車符也是個字元,會被scanf
進去,絕大多數人的解決方案就是提前把這個字元讀取走,但是如果緩衝區的東西太多的話,需要加個迴圈,才能處理,下面我來介紹scanf
的高階用法,之間研究過,忘記在哪裡看到的,這個是我總結的,那些基礎用法自己看看書就行了。
清空快取區
我先把清空緩衝區的程式碼放上,因為後面的程式碼都會用到,至於為什麼後面會有詳細介紹:
scanf("%*[^\n]"); //清除到回車符的所有字元
scanf("%*c"); //清除回車符
指定輸入長度
我們都知道scanf
可以指定小數位數和長度,如下是程式碼示例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int n;
float f;
char str1[23];
scanf("%2d", &n);
//清空緩衝區程式碼{
scanf("%*[^\n]");
scanf("%*c");
//}
scanf("%5f", &f);
//清空緩衝區程式碼{
scanf("%*[^\n]");
scanf("%*c");
//}
scanf("%5s", str1);
puts("執行後:");
printf("n=%d, f=%g, str=%s\n", n, f, str1);
system("pause");
return 0;
}
如下是輸入和輸出結果:
5653 12
2.56458452 2356.9999
helloworld
執行後:
n=56, f=2.564, str=hello
請按任意鍵繼續. . .
看到沒,清空緩衝區的程式碼有效果了,如果沒有這行清空緩衝區的程式碼,就會成這樣子:
5653 12
執行後:
n=56, f=53, str=12
請按任意鍵繼續. . .
這就是清除緩衝區的作用。
單範圍匹配
不要驚訝,scanf
也是支援類似正規表示式的功能的,我們用如下程式碼進行演示:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char str2[30];
scanf("%[abcd]", str2); //%[abcd]表示只要字串只有 a,b,c,d 範圍內就匹配
puts("執行後:");
printf("%s\n", str2);
system("pause");
return 0;
}
如下是輸入和輸出結果:
babccbaxyz
執行後:
babccba
請按任意鍵繼續. . .
程式碼中的註釋可能說的不明白,這裡我長篇大論一下:字串從開頭開始匹配,必須字串只有abcd
中這四個字元任意一個才有效,如果開頭沒有這四個字元,則匹配為空。
多範圍匹配
既然支援單範圍了,肯定也支援多範圍,什麼是多範圍匹配可以先看看一些基礎示例,如果會正規表示式的話很容易懂:
- %[a-z]表示讀取 abc...xyz 範圍內的字元,也即小寫字母;
- %[A-Z]表示讀取 ABC...XYZ 範圍內的字元,也即大寫字母;
- %[0-9]表示讀取 012...789 範圍內的字元,也即十進位制數字;
- %[a-zA-Z]表示讀取大寫字母和小寫字母,也即所有英文字母;
- %[a-z-A-Z0-9]表示讀取所有的英文字母和十進位制數字;
- %[0-9a-f]表示讀取十六進位制數字
如果經常使用的話也就這些型別,如下是程式碼示例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char str3[30];
scanf("%[a-zA-Z]", str3); //只讀取字母
puts("執行後:");
printf("%s\n", str3);
system("pause");
return 0;
}
如下是輸入和輸出結果:
abcXYZ123abcXYZ123
執行後:
abcXYZ
請按任意鍵繼續. . .
不匹配某些字元
既然有匹配的字元,肯定有不想匹配的字元。對於不匹配某些字元,scanf
允許我們在%[ ]
中直接指定某些不能匹配的字元,具體方法就是在不匹配的字元前面加上^
,給幾個例子:
- %[^\n]表示匹配除換行符以外的所有字元,遇到換行符就停止讀取;
- %[^0-9]表示匹配除十進位制數字以外的所有字元,遇到十進位制數字就停止讀取。
如下是程式碼示例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char str11[30], str12[30];
scanf("%[^0-9]", str11);
scanf("%*[^\n]");
scanf("%*c"); //清空緩衝區
scanf("%[^\n]", str12); //等效為gets()
puts("執行後:");
printf("str1=%s \nstr2=%s\n", str11, str12);
system("pause");
return 0;
}
如下是輸入和輸出結果:
abcXYZ@#87edf
Cnblog wingsummer
執行後:
str1=abcXYZ@#
str2=Cnblog wingsummer
請按任意鍵繼續. . .
丟棄資料
scanf
還允許把讀取到的資料直接丟棄,不往變數中存放,具體方法就是在%
後面加一個*
,如下是程式碼示例:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int nn;
char str[30];
scanf("%*d %d", &nn);
scanf("%*[a-z]");
scanf("%[^\n]", str);
puts("執行後:");
printf("n=%d, str=%s\n", nn, str);
system("pause");
return 0;
}
如下是輸入和輸出結果:
100 999abcxyzABCXYZ
執行後:
n=999, str=ABCXYZ
請按任意鍵繼續. . .