首页 » C语言解惑 » C语言解惑全文在线阅读

《C语言解惑》20.5 scanf和sscanf函数

关灯直达底部

这两个函数都是可变参数,函数原型分别为:


int scanf( const char *format [,argument]... );int sscanf (const char *str,const char * format, ...);  

sscanf与scanf类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。

【例20.22】下面是一个进行简单加减法的程序,编译时没有报错,但运行时结果错误,请分析原因并改正。


#include <stdio.h>#include <stdlib.h>int main(){     char op;     int result=0;     int value;     while(1)     {           printf(/"进入运算符和数值:/");           scanf(/"%c %d/",&op,&value);           switch(op){                 case /'+/':                       result+=value;                       break;                 case /'-/':                       result-=value;                       break;                 case /'q/':                       exit(0);                 default:                      printf(/"错误操作数n/");                      break;          }      printf(/"结果:%dn/",result);    }}  

【解答】赋值语句没有错误,但并不能正确读取输入。假如第一次输入“+8”,这一次能正确读入,但在8之后输入一个换行符,这个符号将被第2次读字符时读入op作为操作数,从而造成switch进入default,发生错误。

正如过去分析的那样,将读字符放在最后可以克服这种问题,即


scanf(/"%d %c/",&value,&op);  

但这需先输入数值,再输入操作数。例如原来的顺序是“+8”,现在是“8+”。这样也可以被接收,但要退出来则需要输入数字和q的组合,这很不符合使用的习惯。当然也可以分别使用一个scanf语句接收数据。

用字符数组line,再用fgets函数和sscanf函数相配合,能够满足本题的要求。


//改正的程序#include <stdio.h>#include <stdlib.h>int main(){      char op;      char line[32];      int result=0;      int value;     while(1)     {            printf(/"进入运算符和数值:/");            fgets(line,sizeof(line),stdin);            sscanf(line,/"%c %d/",&op,&value);            switch(op){                 case /'+/':                        result+=value;                        break;                 case /'-/':                        result-=value;                        break;                 case /'q/':                        exit(0);                 default:                        printf(/"错误操作数n/");                        break;             }             printf(/"结果:%dn/",result);      }}  

运行示范如下:


进入运算符和数值:+ 8结果:8进入运算符和数值:+ 7结果:15进入运算符和数值:- 6结果:9进入运算符和数值:q  

20.5.1 sscanf函数的使用方法

函数原型为:


int sscanf (const char *str, const char *format, …);  

sscanf以固定常量字符串str为输入源,格式控制符format参照scanf的格式控制符的使用规则(但更复杂一些),后面可变参数表,用法参照scanf的变量地址表的用法。

由此可见,sscanf会将参数str的字符串根据参数format字符串来转换并格式化数据。格式转换形式参考scanf,转换后的结果存于对应的参数内,参数的形式也是使用参数地址。

返回值:成功则返回参数数目,失败则返回-1,错误原因存于errno中。返回0表示失败,否则表示正确格式化数据的个数。例如语句


sscanf(str,/"%d%d%s/", &i,&i2, &s);  

将从str中顺次读入2个整数给整型变量i1和i2,读入一个字符串给字符串变量s。如果三个都读入成功则返回3,如果只读入了第一个整数到i就返回1,则说明将无法从str读入第二个整数。

字符串str含有字符和数字。使用时可以直接使用“we 123”的形式,也可以用字符串变量。

format的形式比较复杂,可以是一个或多个{%[*][width][{h|l|I64|L}]type|/'/'|/'t/'|/'n/'|非%符号}格式化符号。下面简单解释一下它们的含义。

1.格式含义

(1)*亦可用于格式中(即%*d和%*s),加了星号(*)表示跳过此数据不读入(也就是不把此数据读入参数中)。

(2){a|b|c}表示a、b、c中选一,[d]表示可以有d也可以没有d。

(3)width表示读取宽度。

(4){h|l|I64|L}参数的size,通常h表示单字节size,I表示2字节size,L表示4字节size(double例外),l64表示8字节size。

(5)type就是%s,%d之类的格式。

(6)%*[width][{h|l|I64|L}]type表示满足该条件的将被过滤掉,不会向目标参数中写入值。

2.支持的集合操作

(1)%[a-z]表示匹配a到z中任意字符(尽可能多地匹配)。

(2)%[aB/']匹配a、B、/'中一员。

(3)%[^a]匹配非a的任意字符。

20.5.2 sscanf函数用法举例

【例20.23】典型用法举例。


#include <stdio.h>int main(){     char buf[256];     int a,b;     sscanf(/"1234567 100/", /"%s%d/", buf,&a);     //取字符串和数字     printf(/"%s %#xn/", buf,a);                    //输出字符串和16进制数字     sscanf(/"1234567 /", /"%6s/", buf);     //取6个字符     printf(/"%sn/", buf);     sscanf(/"1234567  abcdedfg/", /"%[^ ]/", buf);          //滤除空格     printf(/"%sn/", buf);     sscanf(/"1234567abcdedfgABCDEFG/", /"%[1-9a-z]/", buf);     //取数字和小写字母     printf(/"%sn/", buf);     sscanf(/"1234567abcdedfgABCDEFG/", /"%[^A-Z]/", buf);     //滤除大写字母     printf(/"%sn/", buf);     sscanf(/"1234 100 9 15/", /"%s%*d%d%d/", buf,&a,&b);     //*跳过数字100     printf(/"%s %#o %#xn/", buf,a,b);               //输出使用标志#     return 0;}  

程序运行结果如下:


1234567 0x6412345612345671234567abcdedfg1234567abcdedfg1234 011 0xf  

【例20.24】对比各种用法的举例。


#include <stdio.h>int main( ){     char buf[256],c[16],c2;     int a,b;     sscanf(/"hello,world! Fine!/", /"%*s%4s/", buf);     //仅取第2个字串的前4个字符     printf(/"%sn/", buf);     sscanf(/"hello, world! Fine!/", /"%*s%5s/", buf);     //仅取world     printf(/"%sn/", buf);     sscanf(/"123,456! 100/", /"%*s%d/", &a);     //仅取数字100     printf(/"%dn/", a);     sscanf(/"abc/[email protected]/",/"%*[^/]/%[^@]/",buf);     //取/和@之间的字符串     printf(/"%sn/", buf);     sscanf(/"ab/[email protected]/[email protected]/",/"%*[^/]/%[^@] %*[^/]/%[^@]/",buf, c);                                          //取/和@之间的字符串     printf(/"%s %sn/", buf, c);     sscanf(/"hel/lo,world! Fine!/", /"%*[^/]/%[^@]/", buf);     //缺省@     printf(/"%sn/", buf);     sscanf(/"he/llo,wor/ld! /[email protected]!/", /"%*[^/]/%[^@]/", buf);     //使用/"//"字符     printf(/"%sn/", buf);     sscanf(/"123Aa321BW%abcFG#abcde/",/"%s/", buf);          //全部字符      printf(/"%sn/", buf);      sscanf(/"123Aa321BWabcFGab&cde/",/"%[1-9a-zA-Z]/", buf);     //遇到其他符号结束      printf(/"%sn/", buf);      sscanf(/"12939488567abcd35edfg89ABCDEFG/", /"%[1-9]/", buf);     //只能提取相邻数字      printf(/"%sn/", buf);      sscanf(/"123a321bWabcFGabcde/",/"%[a-z1-9]/", buf);     //遇到第1个大写字母为止      printf(/"%sn/", buf);      sscanf(/"123a321bWabcFGabcde/",/"%[A-Z1-9]/", buf);     //遇到第1个小写字母为止      printf(/"%sn/", buf);      sscanf(/"123A321BWabcFGabcde/",/"%[1-9A-Z]/", buf);     //遇到第1个小写字母为止      printf(/"%sn/", buf);      //滤除第1个标志之后的所有字符      sscanf(/"1234567abcdedfBgABWZCDEFGBA/", /"%[^A-Z]/", buf);     //滤除B后所有字母      printf(/"%sn/", buf);      sscanf(/"123D4567abcdedfBgABWZCDEFGBA/", /"%[^A-Z]/", buf);     //滤除D后所有字母      printf(/"%sn/", buf);      sscanf(/"2014:05:18 - 2014:06:30/", /"%s %c %s/", buf,&c2,c);     //空格区分      printf(/"%s %c %sn/", buf,c2, c);      sscanf(/"2014:05:18 - 2014:06:30/", /"%s - %s/", buf,c);     //空格区分      printf(/"%s %c %sn/", buf,c2, c);      sscanf(/"2014:05/", /"%d:%d/", &a, &b);               //空格区分      printf(/"%d %dn/", a, b);      sscanf(/"1234 100 9 15/", /"%s%*d%d%d/", buf,&a,&b);     //*跳过数字100      printf(/"%s %#o %#xn/", buf,a,b);               //输出使用标志#      return 0;}输出结果如下:Fineworld100123abcc1 bcdlo,world! Fine!llo,wor/ld! /Fine123Aa321BW%abcFG#abcde123Aa321BWabcFGab12939488567123a321b123123A321BW1234567abcdedf1232014:05:18 - 2014:06:302014:05:18 - 2014:06:302014 51234 011 0xf  

【例20.25】接收输入的例子。


#include <stdio.h>int main(){     char buf[256],c[16],c2;     int a=0,i=0;     double b=0;     for(i=0;i<2;i++)     {            printf(/"依次输入字符、字符串、整数和实数:/");            fgets(buf,sizeof(buf),stdin);            sscanf(buf,/"%c %s %d %lf/",&c2, c,&a, &b);            printf(/"%c %s %d %lfn/",c2,c,a,b);     }     return 0;} 

程序运行示范如下:


依次输入字符、字符串、整数和实数:1 张三 34 55.61 张三 34 55.600000依次输入字符、字符串、整数和实数:3 Hob 23 453 Hob 23 45.000000