声明

文中有些的观点是笔者实验而得,不同的机器环境,可能会得到不同的结果。
例子中的_代表分隔符。

基本概念

从函数名出发

scanf 大致是scan format 的缩写。scan是扫描的意思,format是格式,格式化的意思。函数名一定程度上反映函数的功能,毕竟大佬们是不会随便起名字的。故而,我有下面几个问题:
问题1,扫描的对象是什么?
答案:缓冲区
问题2,扫描是啥意思?具体是怎么扫描的?
答案:此处的扫描,可以理解为读取。按照ASCII码,逐个从缓冲区中读取字符。

问题3,格式是什么?干什么用?
答案:scanf的是第一个参数,是一个字符串,也就是这里的格式。从缓冲区读取的字符,按照这个格式进行校验。符合相应规则的字符,会按照该规则转换并存储到给出的变量中。

开始和结束

在C中,函数就是一个独立的模块,必有开始和结束。函数被调用,该模块就开始执行,开始就不必说了。关于结束,有下面几个问题:
问题4,该函数在什么情况下会结束运行呢?
答案:

  1. 读取完毕
  2. 遇到不符合“格式”的字符

问题5,结束运行后会返回什么?
返回整型,即成功写入的变量的个数。一个也未成功读取的情况下,返回0

工作原理

简述一下,scanf的工作流程。

流程图

文字描述

总的来说,scanf函数是按照格式控制字符串筛选从缓冲区中读取出来的字符,将符合要求的存储到对应变量中。
格式控制字符串,类似正则表达式,是一种规定好的规则。比如: a=%d,b=%d ,其中,a= 是普通字符,会与从缓冲区读取的字符严格比较。也就是说,如果从缓冲区中读取的是a,则符合规则,其他字符则不符合规则,函数终止。%d 类似于正则中的匹配规则,这里的 %d 表示,如果从缓冲区中读取的字符是 int 类型,则符合规则,反之则不符合规则。
常见的格式控制符

数据类型 格式控制符
int %d
char %c
float %f
double %lf

常见的分隔符
空格
制表符
换行
分隔符的作用
1.除%c以外,其他格式控制符会忽略分隔符,从缓冲区中读取,但不做规则校验。
例1 scanf(“%d”, &a); 用户输入123456
运行结果:a存入123。但是456不会被丢弃,存储在缓冲区中,等待被读取。函数返回1
例2 scanf(“
%d”, &a); 用户输入_123___456
运行结果:a存入123。但是456不会被丢弃,存储在缓冲区中,等待被读取。函数返回1
2.%c不会忽略分隔符
例3 scanf(“%c”, &a); 用户输入 回车
运行结果:a存入回车,如果 printf("a=%d\n", a) ,结果为a=10,10为回车的ASCII。函数返回1
例4 scanf(“%c”, &a); 用户输入 空格
运行结果:a存入空格,如果 printf("a=%d\n", a) ,结果为a=32,10为回车的ASCII。函数返回1
例5 scanf(“
%c”, &a); %c之前加了一个空格,例4和5,当用户输入分隔符,再按下回车之后,程序就停止运行,但现在不过你输入多少个分隔符,程序都等待用户输入。也就是说,如果%c之前存在分隔符,将无法读取分隔符。
运行结果:a存入空格,如果 printf("a=%d\n", a) ,结果为a=32,10为回车的ASCII。函数返回1
例6 scanf(“%c”, &a);scanf(“%c”, &b);
用户输入一个空格,按回车结束输入。
printf("a=%d\n", a)
printf("b=%d\n", b)
运行结果 a=32 b=10 不会等待用户的第二次输入,程序直接结束。
如果 scanf("%c", &a);scanf("_%c", &b); 程序运行结果 a=32 b=0,b并未正确读入;如果 scanf("%c", &a);scanf("\n%c", &b);程序将等待用户的第二次输入,忽略读取用户输入的空白符
还是书上描述的清楚