羽夏閑談—— C 的 scanf 的高級用法
前言
今天看到博友發了個有關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
請按任意鍵繼續. . .