scanf特殊結束符


scanf讀入非空格分隔的字符串和整形的混合類型問題
今天在網上看到一個網友提問這樣一個問題:
C語言輸入字符串和數字時如何用逗號隔開,
比如輸入zhang1,90
要求把zhang1賦給一個字符數組
把90付給一個INT的變量。
剛開始只想到如果用scanf("%s,%d",name,&age);  這種方式肯定會出現問題,輸入的數據肯定都會被賦值給字符串,整形數據肯定會是個隨機數,因此給網友回答時說不要將字符串寫在前面,來避免該問題。
后來網友說肯定能實現,因此在網上查了一些資料,終於將該問題解決,如下:
scanf("%[^,],%d",name,&age);
這是scanf的特殊用法,留在這里,提醒自己很多東西還要不斷的去學習。
順便將網上找到的文章貼在這里,以鞏固相關知識。
———————————————————————————————————————————
%[ ] 的用法:%[ ]表示要讀入一個字符集合, 如果[ 后面第一個字符是”^”,則表示反意思。
[ ]內的字符串可以是1或更多字符組成。空字符集(%[])是違反規定的,可
導致不可預知的結果。%[^]也是違反規定的。
%[a-z] 讀取在 a-z 之間的字符串,如果不在此之前則停止,如
char s[]="hello, my friend” ; // 注意: ,逗號在不 a-z之間
sscanf( s, “%[a-z]”, string ) ; // string=hello
%[^a-z]讀取不在 a-z 之間的字符串,如果碰到a-z之間的字符則停止,如
char s[]="HELLOkitty” ; // 注意: ,逗號在不 a-z之間
sscanf( s, “%[^a-z]”, string ) ; // string=HELLO
%*[^=] 前面帶* 號表示不保存變量。跳過符合條件的字符串。
char s[]="notepad=1.0.0.1001" ;
char szfilename [32] = "" ;
int i = sscanf( s, "%*[^=]", szfilename ) ; // szfilename=NULL,因為沒保存
int i = sscanf( s, "%*[^=]=%s", szfilename ) ; // szfilename=1.0.0.1001
%40c 讀取40個字符
The run-time
library does not automatically append a null terminator
to the string, nor does reading 40 characters
automatically terminate the scanf() function. Because the
library uses buffered input, you must press the ENTER key
to terminate the string scan. If you press the ENTER before
the scanf() reads 40 characters, it is displayed normally,
and the library continues to prompt for additional input
until it reads 40 characters
%[^=] 讀取字符串直到碰到’=’號,’^’后面可以帶更多字符,如:
char s[]="notepad=1.0.0.1001" ;
char szfilename [32] = "" ;
int i = sscanf( s, "%[^=]", szfilename ) ; // szfilename=notepad 
如果參數格式是:%[^=:] ,那么也可以從 notepad:1.0.0.1001讀取notepad
使用例子:
char s[]="notepad=1.0.0.1001" ;
char szname [32] = "" ;
char szver [32] = “” ;
sscanf( s, "%[^=]=%s", szname , szver ) ; // szname=notepad, szver=1.0.0.1001
總結:%[]有很大的功能,但是並不是很常用到,主要因為:
1、許多系統的 scanf 函數都有漏洞. (典型的就是 TC 在輸入浮點型時有時會出錯). 
2、用法復雜, 容易出錯. 
3、編譯器作語法分析時會很困難, 從而影響目標代碼的質量和執行效率.
個人覺得第3點最致命,越復雜的功能往往執行效率越低下。而一些簡單的字符串分析我們可以自已處理。
————————————————————————————————————————————————————
一、scanf()函數的一般格式為:scanf("格式字符串",輸入項首地址表)
scanf的格式控制的一般形式為:%[*][寬度][F|N][h|l]類型字符 
[]中的控制字符為可選項 
"*"表示該輸入項讀入后不賦予任何變量,即跳過該輸入值。這在減小內存開支上面還是有一點用處的,不需要的字符直接跳過,免得申請沒用的變量空間 
"寬度"表示輸入讀入字符的長度,對於整型表示截取相應寬度的數字賦給后面列表中的相應變量;對於字符型表示讀入相應長度的字符后把第一個字符賦給相應的變量,其余的自動舍棄。
例如scanf("%2d%3d",&a, &b);如果輸入為12345則將12賦給a,將45賦給b;scanf("%2c%3c",&a, &b);如果輸入為12345則將‘1‘賦給a,將‘3‘賦給b 
F 、N、h、l分別表示遠指針、近指針、短整和長整型,
對於_int64相應的控制字符為ll或I64 "類型字符"為 d -- 輸入十進制整數 、o -- 輸入八進制整數 、x -- 輸入十六進制整數 、u -- 輸入無符號十進制整數 f或e -- 輸入實型數(用小數形式或指數形式) 、c -- 輸入單個字符 、s -- 輸入字符串
二、對於輸入字符串還有一些比較有用的控制: 例如經常需要讀入一行字符串,而這串字符里面可能有空格、制表符等空白字符,如果直接用%s是不可以的,於是有些人就想到用gets(),當然這也是一種選擇,但是懂C的人基本上都知道gets()是一個很危險的函數,而且很難控制,特別是與scanf()交替使用時前者的劣勢更是一覽無余,所以gets()一般是不推薦用的,其實用%[^\n]就可以很好的解決這個問題了, ^表示"",即讀入其后面的字符就結束讀入。這樣想讀入一行字符串直接用scanf("%[^\n]%*c",str);就可以了, %*c的作用是讀入\n,否則后面讀入的將一直是\n。所有對%s起作用的控制都可以用%[], 比如%[0-9]表示只讀入‘0‘到‘9‘之間的字符,%[a-zA-Z]表示只讀入字母, ‘-‘是范圍連接符,當然也可以直接列出你需要讀入的字符,上面讀字母之所以用范圍連接符是因為要輸入52個字符太麻煩了,如果你只需要讀"abc"里面的字符就可以用%[abc] (或者%[cab]、%[acb]、%[a-c]、%[c-a].....), 如果想讀入某個范圍之外的字符串就在前面加一個‘^‘,如:%[^a-z]就表示讀入小寫字母之外的字符上面
這些用法其實可以有很多推廣用法的,比如說你要處理下面的字符串 23 44r f30 88888,3245;34:123. 讓你輸出里面所有的數字,就可以用下面的代碼: 
bool skip(){ scanf("%*[^0-9]"); return true; } 
int main(){
int n; 
while (skip() && scanf("%d", &n)!=EOF) printf("%d\n", n); 
return 0; 
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM