函数原型

int  sscanf( string str, string fmt, mixed var1, mixed var2 ... );
int  scanf( const char *format [,argument]... );

返回值

一般使用scanf函数时都是为某个变量赋值,不考虑它的返回值。但是任何函数都是需要返回的(即使返回类型用void,也可以认为只是调用了return语句,只是并没有返回什么东西而已),同样的scanf函数也是有返回的,它的返回值是成功读取变量的个数。如果有一个输入与变量格式不匹配,那么返回值为0。如:

scanf("%d %d", &num1, &num2);  	

如果输入两个中间有空格隔开的数字(如2 3),那么它的返回值是2。如果输入一个浮点数一个整数,则返回值是1。如果输入一个字符一个整数,则返回值是0。

在输入数据时,遇以下情况时认为该数据结束:

  1. 遇空格,或按“回车”或“跳格”(Tab)键;
  2. 按指定的宽度结束,如“%3d”,只取3列;
  3. 遇非法输入。

format格式解析

format可以是一个或多个

	{%[\*] [width] [{h | l | I64 | L}]type | ' ' | '\t' | '\n' | 非%符号},

注:{a|b|c}表示a,b,c中选一,[d],表示可以有d也可以没有d。

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

    1
    2
    3
    4
    5
    
    const char sourceStr[] = "hello, world";
    char buf[10] = {0};
    sscanf(sourceStr, "%*s%s", buf); //%*s表示第一个匹配到的%s被过滤掉,即hello被过滤了
    cout << buf<< endl;
    结果为:world
    

    ``

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

  3. width表示读取宽度。

    用法如下:

    1
    2
    3
    4
    5
    
    const char sourceStr[] = "hello, world";
    char buf[10] = {0};
    sscanf(sourceStr, "%5s", buf); //%5s,只取5个字符
    cout << buf<< endl;
    结果为:hello
    

    ``

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

  5. type :这就很多了,就是%s,%d之类。

格式匹配

scanf函数的<格式化字符串>与后面的<地址表>是必须严格匹配的。注意,是严格匹配,可以说不能有丝毫差别,但对于连续多个空格可以等同于一个空格。

格式匹配使用贪婪算法,即匹配尽可能多的匹配字符。

1
2
3
4
5
6
char str[10],int x;
scanf("%s:%d",str,&amp;x);
printf(%s %d,str,x);
//输入 kryptosx:001
//你预计输出 kryptosx 001
//但事实上输出 kryptosx:001 4252772

这是因为%s在匹配时直接把”kryptosx:001“全匹配掉了,应为贪心要求尽可能的匹配。4252772是x未初始化的值,因为x并没有匹配到输入。

type类型

%c 一个单一的字符
%d 一个十进制整数
%i 一个整数
%e, %f, %g 一个浮点数
%o 一个八进制数
%s 一个字符串
%x 一个十六进制数
%p 一个指针
%n 一个等于读取字符数量的整数
%u 一个无符号整数
%[] 一个字符集
%% 一个精度符

对于scanf函数的%c格式转换符,可以接受任何的非空白字符或空白字符(包括空格、回车、Tab甚至是F2这样的字符)。

集合操作

[ ]是个集合的标志,%[ ]特指读入此集合所限定的那些字符,比如%[A-Z]是输入大写字母,一旦遇到不在此集合的字符便停止。如果集合的第一个字符是“^”,这说明读取不在"^“后面集合的字符,既遇到”^“后面集合的字符便停止(这就是scanf函数里的正则表达式应用)。注意:此时读取的字符串是可以含有空格的。

%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)

%[aB’] 匹配a、B、‘中一员,贪婪性

%[^a] 匹配非a的任意字符,贪婪性

这和正则表达式很相似,而且仍然支持过滤,即可以有%*[a-z].如:

1
2
3
4
const char* s = "iios/12DDWDFF@122";
char buf[20];
sscanf( s, "%*[^/]/%[^@]", buf );
printf( "%s\n", buf );

先将 “iios/“过滤掉,再将非’@‘的一串内容送到buf中,cool.得到结果。

怎样从sip:tom@172.18.1.133中取出tom?

1
2
3
char * url="<sip:tom@172.18.1.133>";
char uri[10]={0};
sscanf(url,"%*[^:]:%[^@]",uri);

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <stdio.h>
int main()
{
 char buf[512] = {0};
//1. 常见用法。
 sscanf("123456 asdf", "%s", buf);
 printf("%s/n", buf);
 printf("123456 Expect! %%s/n/n");
//结果为:123456
//2. 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。
 sscanf("123456 ", "%4s", buf);
 printf("%s/n", buf);
  printf("1234 Expect! %%4s/n/n");
//结果为:1234
//3. 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。
 sscanf("123456 abcdedf", "%[^ ]", buf);
 printf("%s/n", buf);
 printf("123456 Expect! %%[^ ]/n/n");
//结果为:123456
//4.  取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。
 sscanf("123456abcdedfBCDEFxyz", "%[1-9a-z]", buf);
 printf("%s/n", buf);
 printf("123456abcdedf Expect! %%[1-9a-z]/n/n");
//结果为:123456abcdedf
//5.  取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。
 sscanf("123456 abcdedfBCDEFxyz", "%[^A-Z]", buf);
 printf("%s/n", buf);
  printf("123456 abcdedf Expect! %%[^A-Z]/n/n");
//结果为:123456 abcdedf
//6、给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中
 sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);
 printf("%s/n", buf);
 printf("12DDWDFF Expect! %%*[^/]/%%[^@]/n/n");
//结果为:12DDWDFF
//7、给定一个字符串““hello, world”,仅保留world。(注意:“,”之后有一空格)
 sscanf("hello, world",  "%*s%s",  buf);
 printf("%s/n", buf);
 printf("world Expect! %%*s%%s/n/n");
//结果为:world 
//8、参数size的控制
 unsigned char m[6] = {0};
 int n = 0;
// sscanf 返回输入了几个参数
 n = sscanf("010203040506", "%hhx%hhx%hhx%hhx%hhx%hhx", &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]);
 printf("hhx: %d :%02x%02x%02x%02x%02x%02x/n",n, m[0], m[1],m[2],m[3], m[4], m[5]);
// 结果 n 为 1, 因为 hhx 把所有字符串作为一个数字,后面的都没有输入
        
 n = sscanf("010203040506", "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]);
 printf("2hhx: %d :%02x%02x%02x%02x%02x%02x/n",n, m[0], m[1],m[2],m[3], m[4], m[5]);
// 结果 n 为 6, 加了2,之后限制每次hhx只匹配2个字符,所以每个都被输入
 n = sscanf("010203040506", "%02x%02x%02x%02x%02x%02x", &m[0], &m[1], &m[2], &m[3], &m[4], &m[5]);
 printf(" 02x: %d :%02x%02x%02x%02x%02x%02x/n",n, m[0], m[1],m[2],m[3], m[4], m[5]);
// 0 是填充字符,2表示匹配2个字符,x表示一个十六进制数
// 注意:编译有warning,有时结果是正确的(跟具体的编译器、编译选项、编译环境有关),但x表示4个字节,大于被输入对象的大小
// 这会导致相邻的3个字节会被覆盖!!这会导致分配在相邻内存的变量被清0
//http://blog.csdn.net/rainharder/archive/2008/09/27/2989675.aspx里面有个覆盖的例子
 return 0;
}