c语言scanf用法详解

看了一下glibc scanf的源码之后,对scanf的使用方法有了更深入的理解,下面给大家讲解一下scanf函数的用法.

1.以%开头的字符串

%[argpos$] [I'*] [maximum field width] [type modifiers] [arg]
  1. argpos: 指定了参数的位置
  2. I’*
    • I:use locale’s digits
    • ': Group numbers
    • *: 跳过这个参数
  3. maximum field width : 从输入的内容中最多读取几个字符
  4. type modifiers:
    - hh 写 一个字节
    - h 写两个字节
    - 写四个字节
    - l 写八个字节
    - ll 写八个字节
    - m 有scanf分配缓冲区
  5. arg
    - % 输出%
    - n将前面已经读取的字符个数写到参数指定的位置
    - c 字符
    - C wchar_t
    - s 字符串
    - S wchar_t字符串
    - p 地址
    - x/X 十六进制字符串
    - u/d 无符号/有符号整数
    - e/E/f/F 浮点数
    - [] []内字符以外的字符作为定界符
    - [^] [] 内的字符作为定界符

2.非%开头的字符串

读取一个字符,与之相比较,不同的话scanf失败。

3.演示

3.1 例1

char*p = NULL;
int n = 0;
scanf("Hello%2$10ms%3$n",0,&p,&n);

解析流程:

  1. scanf会从格式串的第一个字符开始遍历,若字符不是%,那么与读入的字符相比较,相同的话,遍历下一个字符。
  2. 当scanf遇到%的时候,之后读取到了2,读取到$后,scanf会把数据保存在第二个参数
  3. 继续解析10 ,这个10的含义就是,从输入的内容中最多读取10个字符。
  4. 解析到m,scanf会自己创建一个缓冲区,把从输入的内容中转换的结果写到这个缓冲区内,最后把缓冲区地址写到参数指定的位置
  5. 解析到s,scanf之后将会读取字符串到指定的buffer内.
  6. 后面的%3 $n同理,scanf会把前面已经读取的字符数写到第三个参数指定的地址处。

接着我们输入 HelloAAAAAAAAAAAA
Hello与格式串中开始位置的Hello相匹配,继续看后面
%2$10ms,最多读取10个字符,并且自己创建缓冲区,把字符串,也就是10个A读到自己创建的缓冲区内,并把地址写到第二个参数指定的位置。
%3 $n ,前面读取了15个字符,所以这里会把15写到第三个参数指定的位置
运行看一下:
c语言scanf用法详解_第1张图片

再输入内容 Helaaaaaa看一下,匹配成功三个字符,然后第四个失败,scanf结束,最后p 任然是0,n任然为0

c语言scanf用法详解_第2张图片

3.2 例二

int val = 0;
scanf("Haha%2$10hhd",0,&val);

解析流程:

  1. 匹配Haha
  2. 2$将转换后的结果写到第二个参数指定的位置
  3. 10从输入内容中最多读取10个字符
  4. 只写1个字节

接下来输入内容Haha000000000000000123,由于匹配Haha之后最多读取10个字符,所以最后得到的整数是0。
c语言scanf用法详解_第3张图片
接着我把这里val的初始值改一下,改为0xabcd,然后输入同样的内容。
c语言scanf用法详解_第4张图片
最后的val并不是0,为什么呢???
原因是我们这里指定了只写一个字节.所以最后val的值是0xab00,只有低字节发生了变化。
c语言scanf用法详解_第5张图片

3.3例三

char buffer[256] = {0};
int n = 0;
scanf("Hello%2$10[^abc]%1$n",&n,buffer);

解析流程:

  1. 匹配Hello
  2. 2$将转换结果写到第二个参数指定的位置
  3. 10最多读取10个字符
  4. [^abc],abc这三个字符中的任意一个都是定界符
  5. %1 $n将前面读取的字符个数写到第一个参数指定的位置

接下来输入内容: Hellohhhhhhhhhhhh,匹配Hello之后,最多读取10个字符到第二个参数里面,所以最后buffer里面有10个h,%1 $n,解析到这里时,前面读取了15 个字符,所以会把15写到n里面。
c语言scanf用法详解_第6张图片
接下来输入 Hellohhhhhh,然后按下回车,我们会发现,什么也没输出。
c语言scanf用法详解_第7张图片
为什么呢???因为我们指定了定界符为abc,此时的换行符已经不是定界符了,换行符也被读到了buffer里面。
我们继续输入gga,然后回车。scanf会把gg读到buffer里面,然后遇到a,结束。一共读取了 5(Hello) + 6 (hhhhhh) + 1 (\n) + 2(gg) = 14个字符
c语言scanf用法详解_第8张图片
并且我们可以发现,hhhhhh和gg中间是有一个换行符的,说明换行符确实被读进去了。

End

上面这些用法是我在阅读scanf的源码时发现的,(glibc-2.23),msvc上可能有一部分功能是无法使用的,或者某些功能并不是标准里面含有的。有一部分这里没有介绍到,感兴趣的话大家自己实验吧(有些没用过,代码太多,最后懒得看了,毕竟主要是为了找到哪里调用了malloc来触发malloc_hook)

你可能感兴趣的:(pwn入门,C语言,c语言,开发语言)