看了一下glibc scanf的源码之后,对scanf的使用方法有了更深入的理解,下面给大家讲解一下scanf函数的用法.
%[argpos$] [I'*] [maximum field width] [type modifiers] [arg]
读取一个字符,与之相比较,不同的话scanf失败。
char*p = NULL;
int n = 0;
scanf("Hello%2$10ms%3$n",0,&p,&n);
解析流程:
接着我们输入 HelloAAAAAAAAAAAA
Hello与格式串中开始位置的Hello相匹配,继续看后面
%2$10ms,最多读取10个字符,并且自己创建缓冲区,把字符串,也就是10个A读到自己创建的缓冲区内,并把地址写到第二个参数指定的位置。
%3 $n ,前面读取了15个字符,所以这里会把15写到第三个参数指定的位置
运行看一下:
再输入内容 Helaaaaaa看一下,匹配成功三个字符,然后第四个失败,scanf结束,最后p 任然是0,n任然为0
int val = 0;
scanf("Haha%2$10hhd",0,&val);
解析流程:
接下来输入内容Haha000000000000000123,由于匹配Haha之后最多读取10个字符,所以最后得到的整数是0。
接着我把这里val的初始值改一下,改为0xabcd,然后输入同样的内容。
最后的val并不是0,为什么呢???
原因是我们这里指定了只写一个字节.所以最后val的值是0xab00,只有低字节发生了变化。
char buffer[256] = {0};
int n = 0;
scanf("Hello%2$10[^abc]%1$n",&n,buffer);
解析流程:
接下来输入内容: Hellohhhhhhhhhhhh,匹配Hello之后,最多读取10个字符到第二个参数里面,所以最后buffer里面有10个h,%1 $n,解析到这里时,前面读取了15 个字符,所以会把15写到n里面。
接下来输入 Hellohhhhhh,然后按下回车,我们会发现,什么也没输出。
为什么呢???因为我们指定了定界符为abc,此时的换行符已经不是定界符了,换行符也被读到了buffer里面。
我们继续输入gga,然后回车。scanf会把gg读到buffer里面,然后遇到a,结束。一共读取了 5(Hello) + 6 (hhhhhh) + 1 (\n) + 2(gg) = 14个字符
并且我们可以发现,hhhhhh和gg中间是有一个换行符的,说明换行符确实被读进去了。
上面这些用法是我在阅读scanf的源码时发现的,(glibc-2.23),msvc上可能有一部分功能是无法使用的,或者某些功能并不是标准里面含有的。有一部分这里没有介绍到,感兴趣的话大家自己实验吧(有些没用过,代码太多,最后懒得看了,毕竟主要是为了找到哪里调用了malloc来触发malloc_hook)