scanf 用%i能夠獲得8/16進(jìn)制的值, 比如0011就是9,0x11就是17,當(dāng)然如果讀取到08或者09就會(huì)出錯(cuò)了。
scanf簡介
scanf函數(shù),與printf函數(shù)一樣,都被定義在stdio.h 里,因此在使用scanf函數(shù)時(shí)要加上#include<stdio.h> 。它是格式輸入函數(shù),即按用戶指定的格式從鍵盤上把數(shù)據(jù)輸入到指定的變量之中,其關(guān)鍵字最末一個(gè)字母f即為“格式”(format)之意
scanf函數(shù)的一般形式scanf(格式控制,地址表列) int scanf(char *format[,argument,...]); “格式控制”的含義同printf函數(shù);“地址表列”是由若干個(gè)地址組成的表列,可以是變量的地址,或字符串的首地址。 scanf()函數(shù)返回成功賦值的數(shù)據(jù)項(xiàng)數(shù),讀到文件末尾出錯(cuò)時(shí)則返回EOF。 例:使用scanf函數(shù)輸入數(shù)據(jù)。 在visual c++ 6.0上的編寫方式。
[cpp] view plain
copy print ?
#include<stdio.h> ??void ?main()??{?? ????int ?a,b,c;?? ????printf("please?input?a,b,c" );?? ????scanf("%d,%d,%d" ,&a,&b,&c);?? ????printf("a=%d,b=%d,c=%d" ,a,b,c);?? }??
#include<stdio.h>
void main()
{int a,b,c;printf("please input a,b,c");scanf("%d,%d,%d",&a,&b,&c);printf("a=%d,b=%d,c=%d",a,b,c);
}
在Dev-C++上運(yùn)行程序?yàn)?#xff1a;
[cpp] view plain
copy print ?
#include<stdio.h> ??int ?main()??{?? ????int ?a,b,c;?? ????printf("please?input?a,b,c" );?? ????scanf("%d,%d,%d" ,&a,&b,&c);?? ????printf("a=%d,b=%d,c=%d" ,a,b,c);?? ????fflush(stdin);?? ????getchar();?? }??
#include<stdio.h>
int main()
{int a,b,c;printf("please input a,b,c");scanf("%d,%d,%d",&a,&b,&c);printf("a=%d,b=%d,c=%d",a,b,c);fflush(stdin);getchar();
}
注意上面的scanf("%d,%d,%d",&a,&b,&c);中%d,%d,%d之間有逗號,在輸入數(shù)據(jù)時(shí)也要加逗號,如果去掉逗號,輸入時(shí)就不用逗號,而用空格,tab鍵或回車鍵將各個(gè)數(shù)據(jù)隔開
格式字符說明%a,%A 讀入一個(gè)浮點(diǎn)值(僅C99有效) %c 讀入一個(gè)字符 %d 讀入十進(jìn)制整數(shù) %i 讀入十進(jìn)制,八進(jìn)制,十六進(jìn)制整數(shù) %o 讀入八進(jìn)制整數(shù) %x,%X 讀入十六進(jìn)制整數(shù) %s 讀入一個(gè)字符串,遇空格、制表符或換行符結(jié)束。 %f,%F,%e,%E,%g,%G 用來輸入實(shí)數(shù),可以用小數(shù)形式或指數(shù)形式輸入。 %p 讀入一個(gè)指針 %u 讀入一個(gè)無符號十進(jìn)制整數(shù) %n 至此已讀入值的等價(jià)字符數(shù) %[] 掃描字符集合 %% 讀%符號 附加格式說明字符表修飾符說明 L/l 長度修飾符 輸入"長"數(shù)據(jù) h 長度修飾符 輸入"短"數(shù)據(jù) W 整型常數(shù) 指定輸入數(shù)據(jù)所占寬度 * 表示本輸入項(xiàng)在讀入后不賦值給相應(yīng)的變量
scanf的返回值scanf的返回值有后面的參數(shù)決定 scanf("%d%d", &a, &b); 如果a和b都被成功讀入,那么scanf的返回值就是2 如果只有a被成功讀入,返回值為1 如果a和b都未被成功讀入,返回值為0 如果遇到錯(cuò)誤或遇到end of file,返回值為EOF。 且返回值為int型.
使用scanf函數(shù)時(shí)應(yīng)該注意的問題
1、scanf()中的變量必須使用地址。
2、scanf()的格式控制串可以使用其它非空白字符,但在輸入時(shí)必須輸入這些字符。
3、在用"%c"輸入時(shí),空格和“轉(zhuǎn)義字符”均作為有效字符。
問題一
?scanf()函數(shù)不能正確接受有空格的字符串?如: I love you!
[cpp] view plain
copy print ?
#include?<stdio.h> ??int ?main()??{?? ????char ?str[80];?? ????scanf("%s" ,str);?? ????printf("%s" ,str);?? ????return ?0;?? }??
#include <stdio.h>
int main()
{char str[80];scanf("%s",str);printf("%s",str);return 0;
}
輸入:I love you! 輸出:scanf()函數(shù)接收輸入數(shù)據(jù)時(shí),遇以下情況結(jié)束一個(gè)數(shù)據(jù)的輸入:(不是結(jié)束該scanf函數(shù),scanf函數(shù)僅在每一個(gè)數(shù)據(jù)域均有數(shù)據(jù),并按回車后結(jié)束)。 ① 遇空格、“回車”、“跳格”鍵。 ② 遇寬度結(jié)束。 ③ 遇非法輸入。 所以,上述程序并不能達(dá)到預(yù)期目的,scanf()掃描到"I"后面的空格就認(rèn)為對str的賦值結(jié)束,并忽略后面的"love you!".這里要注意是"love you!"還在鍵盤緩沖區(qū)(關(guān)于這個(gè)問題,網(wǎng)上我所見的說法都是如此,但是,我經(jīng)過調(diào)試發(fā)現(xiàn),其實(shí)這時(shí)緩沖區(qū)字符串首尾指針已經(jīng)相等了,也就是說緩沖區(qū)清空了,scanf()函數(shù)應(yīng)該只是掃描stdin流,這個(gè)殘存信息是在stdin中)。我們改動(dòng)一下上面的程序來驗(yàn)證一下:
[cpp] view plain
copy print ?
#include?<stdio.h> ??#include<windows.h> ??int ?main()??{?? ????char ?str[80];?? ????char ?str1[80];?? ????char ?str2[80];?? ????scanf("%s" ,str);?? ????printf("%s" ,str);?? ????Sleep(5000);?? ? ?? ????scanf("%s" ,str2);?? ????printf("/n%s" ,str1);?? ????printf("/n%s" ,str2);?? ????return ?0; ?? }??
#include <stdio.h>
#include<windows.h>
int main()
{char str[80];char str1[80];char str2[80];scanf("%s",str);/*此處輸入:I love you! */printf("%s",str);Sleep(5000);/*這里等待5秒,告訴你程序運(yùn)行到什么地方*/ /*不是sleep(5) 1,函數(shù)名是Sleep不是sleep。2,C/C++中,unsigned Sleep(unsigned)應(yīng)該是毫秒ms.scanf("%s",str1);/*這兩句無需你再輸入,是對鍵盤盤緩沖區(qū)再掃描 */scanf("%s",str2);/*這兩句無需你再輸入,是對鍵盤盤緩沖區(qū)再掃描 */printf("/n%s",str1);printf("/n%s",str2);return 0;
}
輸入:I love you! 輸出: I love you! 好了,原因知道了,那么scanf()函數(shù)能不能完成這個(gè)任務(wù)?回答是:能!別忘了scanf()函數(shù)還有一個(gè) %[] 格式控制符(如果對%[]不了解的請查看本文的上篇),請看下面的程序:
[cpp] view plain
copy print ?
#include?"stdio.h" ??int ?main()??{?? ????char ?string[50];?? ????scanf("%[^/n]" ,string);?? ????printf("%s/n" ,string);?? ????return ?0;?? }??
#include "stdio.h"
int main()
{char string[50];/*scanf("%s",string);不能接收空格符*/scanf("%[^/n]",string);printf("%s/n",string);return 0;
}
?
問題二
?鍵盤緩沖區(qū)殘余信息問題
[cpp] view plain
copy print ?
#include?<stdio.h> ??int ?main()??{?? ????int ?a;?? ????char ?c;??? ????do {?? ????????scanf("%d" ,&a);?? ????????scanf("%c" ,&c);?? ????????printf("a=%d?c=%c/n" ,a,c);?? ????}while (c!='N' );?? }??
#include <stdio.h>
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()函數(shù)賦給C到底是什么,結(jié)果是c=10 ,ASCII值為10是什么?換行即/n.對了,我們每擊打一下"Enter"鍵,向鍵盤緩沖區(qū)發(fā)去一個(gè)“回車”(/r),一個(gè)“換行"(/n),在這里/r被scanf()函數(shù)處理掉了(姑且這么認(rèn)為吧^_^),而/n被scanf()函數(shù)“錯(cuò)誤”地賦給了c.解決辦法:可以在兩個(gè)scanf()函數(shù)之后加個(gè)fflush(stdin);,還有加getch()?, getchar()也可以,但是要視具體scanf()語句加那個(gè),這里就不分析了,讀者自己去摸索吧。但是加fflush(stdin);不管什么情況都可行。 ( 函數(shù)名: fflush 功 能: 清除一個(gè)流 用 法: int fflush(FILE *stream); )
[cpp] view plain
copy print ?
#include?<stdio.h> ??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 <stdio.h>
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');
}
這里再給一個(gè)用“空格符”來處理緩沖區(qū)殘余信息的示例:運(yùn)行出錯(cuò)的程序:
[cpp] view plain
copy print ?
#include?<stdio.h> ??int ?main()??{?? ????int ?i;?? ????char ?j;?? ????for (i?=?0;i?<?10;i++)?? ????{?? ????????scanf("%c" ,&j);?? ????}?? }??
#include <stdio.h>
int main()
{int i;char j;for(i = 0;i < 10;i++){scanf("%c",&j);/*這里%前沒有空格*/}
}
使用了空格控制符后:
[cpp] view plain
copy print ?
#include?<stdio.h> ??int ?main()??{?? ????int ?i;?? ????char ?j;?? ????for (i?=?0;i?<?10;i++)?? ????{?? ????????scanf("?%c" ,&j);?? ????}?? }??
#include <stdio.h>
int main()
{int i;char j;for(i = 0;i < 10;i++){scanf(" %c",&j);/*注意這里%前有個(gè)空格*/}
}
可以運(yùn)行看看兩個(gè)程序有什么不同。
問題三
?如何處理scanf()函數(shù)誤輸入造成程序死鎖或出錯(cuò)?
[cpp] view plain
copy print ?
#include?<stdio.h> ??int ?main()??{?? ????int ?a,b,c;??? ????scanf("%d,%d" ,&a,&b);?? ????c=a+b;?? ????printf("%d+%d=%d" ,a,b,c);?? }??
#include <stdio.h>
int main()
{int a,b,c; /*計(jì)算a+b*/scanf("%d,%d",&a,&b);c=a+b;printf("%d+%d=%d",a,b,c);
}
如上程序,如果正確輸入a,b的值,那么沒什么問題,但是,你不能保證使用者每一次都能正確輸入,一旦輸入了錯(cuò)誤的類型,你的程序不是死鎖,就是得到一個(gè)錯(cuò)誤的結(jié)果,呵呵,這可能所有人都遇到過的問題吧?解決方法:scanf()函數(shù)執(zhí)行成功時(shí)的返回值是成功讀取的變量數(shù),也就是說,你這個(gè)scanf()函數(shù)有幾個(gè)變量,如果scanf()函數(shù)全部正常讀取,它就返回幾。但這里還要注意另一個(gè)問題,如果輸入了非法數(shù)據(jù),鍵盤緩沖區(qū)就可能還個(gè)有殘余信息問題。正確的例程:
[cpp] view plain
copy print ?
#include?<stdio.h> ??int ?main()??{?? ????int ?a,b,c;??? ????while (scanf("%d,%d" ,&a,&b)!=2)?? ????????fflush(stdin);?? ????c=a+b;?? ????printf("%d+%d=%d" ,a,b,c);?? }??
#include <stdio.h>
int main()
{int a,b,c; /*計(jì)算a+b*/while(scanf("%d,%d",&a,&b)!=2)fflush(stdin);c=a+b;printf("%d+%d=%d",a,b,c);
}
?
補(bǔ)充
?fflush(stdin)這個(gè)方法在GCC下不可用。(在VC6.0下可以) 以下是 C99 對 fflush 函數(shù)的定義: int fflush(FILE *stream); 如果stream指向輸出流或者更新流(update stream),并且這個(gè)更新流 最近執(zhí)行的操作不是輸入,那么fflush函數(shù)將把任何未被寫入的數(shù)據(jù)寫入stream 指向的文件(如標(biāo)準(zhǔn)輸出文件stdout)。否則,fflush函數(shù)的行為是不確定的。 fflush(NULL)清空所有輸出流和上面提到的更新流。如果發(fā)生寫錯(cuò)誤,fflush 函數(shù)會(huì)給那些流打上錯(cuò)誤標(biāo)記,并且返回EOF,否則返回0。 由此可知,如果 stream 指向輸入流(如 stdin),那么 fflush 函數(shù)的行為是不確定的。故而使用 fflush(stdin) 是不正確的,至少是移植性不好的。 可采用如下方法: /* 此函數(shù)可以和scanf函數(shù)一起使用,但使用%c輸入時(shí)要注意,即此函數(shù)只能用于緩沖區(qū)非空的情況 */
void flush()
{
??? char c;
??? while ((c=getchar()) != '/n'&&c!=EOF) ;
}
[cpp] view plain
copy print ?
#include?<stdio.h> ??int ?main()??{?? ????int ?a,b,c;??? ????while (scanf("%d,%d" ,&a,&b)!=2)??? ????????flush();?? ????c=a+b;?? ????printf("%d+%d=%d" ,a,b,c);?? }??
#include <stdio.h>
int main()
{int a,b,c; /*計(jì)算a+b*/while(scanf("%d,%d",&a,&b)!=2) flush();c=a+b;printf("%d+%d=%d",a,b,c);
}
?sscanf介紹
sscanf() - 從一個(gè)字符串中讀進(jìn)與指定格式相符的數(shù)據(jù).
函數(shù)原型:
int sscanf( const char *, const char *, ...);
int sscanf(const char *buffer,const char *format,[argument ]...);
buffer 存儲的數(shù)據(jù)
format 格式控制字符串
argument 選擇性設(shè)定字符串
sscanf會(huì)從buffer里讀進(jìn)數(shù)據(jù),依照argument的設(shè)定將數(shù)據(jù)寫回。
說明:
sscanf與scanf類似,都是用于輸入的,只是后者以鍵盤(stdin)為輸入源,前者以固定字符串為輸入源。 第一個(gè)參數(shù)可以是一個(gè)或多個(gè) {%[*] [width] [{h | l | I64 | L}]type | ' ' | '\t' | '\n' | 非%符號}
注: 1、 * 亦可用于格式中, (即 %*d 和 %*s) 加了星號 (*) 表示跳過此數(shù)據(jù)不讀入. (也就是不把此數(shù)據(jù)讀入?yún)?shù)中) 2、{a|b|c}表示a,b,c中選一,[d],表示可以有d也可以沒有d。 3、width表示讀取寬度。 4、{h | l | I64 | L}:參數(shù)的size,通常h表示單字節(jié)size,I表示2字節(jié) size,L表示4字節(jié)size(double例外),l64表示8字節(jié)size。 5、type :這就很多了,就是%s,%d之類。 6、特別的:%*[width] [{h | l | I64 | L}]type 表示滿足該條件的被過濾掉,不會(huì)向目標(biāo)參數(shù)中寫入值 失敗返回0 ,否則返回格式化的參數(shù)個(gè)數(shù) 支持集合操作 %[a-z] 表示匹配a到z中任意字符,貪婪性(盡可能多的匹配) %[aB'] 匹配a、B、'中一員,貪婪性 %[^a] 匹配非a的任意字符,并且停止讀入,貪婪性 例子 1. 常見用法。 char buf[512] ; sscanf("123456 ", "%s", buf);//此處buf是數(shù)組名,它的意思是將123456以%s的形式存入buf中! printf("%s\n", buf); 結(jié)果為:123456 2. 取指定長度的字符串。如在下例中,取最大長度為4字節(jié)的字符串。 sscanf("123456 ", "%4s", buf); printf("%s\n", buf); 結(jié)果為:1234 3. 取到指定字符為止的字符串。如在下例中,取遇到空格為止字符串。 sscanf("123456 abcdedf", "%[^ ]", buf); printf("%s\n", buf); 結(jié)果為:123456 4. 取僅包含指定字符集的字符串。如在下例中,取僅包含1到9和小寫字母的字符串。 sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf); printf("%s\n", buf); 結(jié)果為:123456abcdedf 當(dāng)輸入: sscanf("123456abcdedfBCDEF","%[1-9A-Z]",buf); printf("%s\n",buf); 結(jié)果為:123456 5. 取到指定字符集為止的字符串。如在下例中,取遇到大寫字母為止的字符串。 sscanf("123456abcdedfBCDEF", "%[^A-Z]", buf); printf("%s\n", buf); 結(jié)果為:123456abcdedf 6、給定一個(gè)字符串iios/12DDWDFF@122,獲取 / 和 @ 之間的字符串,先將 "iios/"過濾掉,再將非'@'的一串內(nèi)容送到buf中 sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf); printf("%s\n", buf); 結(jié)果為:12DDWDFF 7、給定一個(gè)字符串"hello, world",僅保留world。(注意:","之后有一空格,%s遇空格停止,加*則是忽略第一個(gè)讀到的字符串) sscanf("hello, world", "%*s%s", buf); printf("%s\n", buf); 結(jié)果為:world %*s表示第一個(gè)匹配到的%s被過濾掉,即hello被過濾了 如果沒有空格則結(jié)果為NULL。 sscanf的功能很類似于正則表達(dá)式, 但卻沒有正則表達(dá)式強(qiáng)大,所以如果對于比較復(fù)雜的字符串處理,建議使用正則表達(dá)式. //------------------------------------------------------- 用它來分隔類似這樣的字符串2006:03:18: int a, b, c; /*sscanf("2006:03:18", "%d:%d:%d", a, b, c); */ /*錯(cuò)誤方法, 要在變量a,b,c前加上取地址符, modified by huanmie_09*/ sscanf("2006:03:18", "%d:%d:%d", &a, &b, &c); 以及2006:03:18 - 2006:04:18: char sztime1[16] = "", sztime2[16] = ""; sscanf("2006:03:18 - 2006:04:18", "%s - %s", sztime1, sztime2); 但是后來,我需要處理2006:03:18-2006:04:18 僅僅是取消了‘-’兩邊的空格,卻打破了%s對字符串的界定。 我需要重新設(shè)計(jì)一個(gè)函數(shù)來處理這樣的情況?這并不復(fù)雜,但是,為了使所有的代碼都有統(tǒng)一的風(fēng)格,我需要改動(dòng)很多地方,把已有的sscanf替換成我自己的分割函數(shù)。我以為我肯定需要這樣做,并伴隨著對sscanf的強(qiáng)烈不滿而入睡;一覺醒來,發(fā)現(xiàn)其實(shí)不必。 format-type中有%[]這樣的type field。如果讀取的字符串,不是以空格來分隔的話,就可以使用%[]。 %[]類似于一個(gè)正則表達(dá)式。[a-z]表示讀取a-z的所有字符,[^a-z]表示讀取除a-z以外的所有字符。 所以那個(gè)問題也就迎刃而解了: sscanf("2006:03:18 - 2006:04:18", "%[0-9,:] - %[0-9,:]", sztime1, sztime2); //-------非本段作者--------------------------------------------------------------------------------------------------- sscanf("2006:03:18-2006:04:18","%[^-]-%s",sztime1,sztime2); 描述:%[^-]匹配到‘-’默認(rèn)為存到sztime1的字符串“2006:03:18”加空格符,所以%s會(huì)默認(rèn)輸入“-2006:04:18”到sztime2這也就是%s前面加‘-’的原因。輸出跟作者一樣,但更易懂、易讀。 //----------------------------------------------------------------------------------------------------end----------------- 在softmse (Jake) 的問題貼http://community.csd(去掉我)n.n(去掉我)et/Expert/topic/4843/4843294.xml?temp=.4321558中 ,給出了一個(gè)很cool的sscanf用例,而后通過學(xué)習(xí),發(fā)現(xiàn)sscanf真棒,現(xiàn)做一總結(jié)。 原問題: iios/12DDWDFF@122 獲取/和@之間的字符串怎么做 C程序里面有什么函數(shù)嗎? 代碼: #include <stdio.h> int main() { const char* s = "iios/12DDWDFF@122"; char buf[20]; sscanf( s, "%*[^/]/%[^@]", buf ); printf( "%s\n", buf ); return 0; } 結(jié)果為:12DDWDFF
總結(jié)
以上是生活随笔 為你收集整理的%d 跟%i 的区别以及scanf和sscanf的用法 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。