1、标准输入缓冲区与堆区、栈区、静态区等一样都是存在于程序运行时所形成的进程中。
2、若标准输入缓冲区为空,则程序会暂停,即进程阻塞,会持续等待输入。
3、键盘输入就是标准输入,键盘输入的任何东西都是标准输入(包括回车符)。
4、标准输入存放于输入缓冲区,用于标准输入函数scanf()
来读取,回车符不仅是标准输入的内容,还是scanf()
匹配读取操作的启动键。
5、匹配规则如下:
(1)scanf()函数括号中的占位符会依据自己的规格来匹配标准输入缓冲区中每个字符,%d匹配整数,%f或%lf匹配小数(匹配的是第一个小数点前的所有整数、第一个小数点、第一个小数点后的所有整数
),%c匹配字符。
(2)当占位符为%d
时,scanf("%d",地址)
会连续读取匹配成功的字符,直到遇见匹配不成功的字符,例如:
标准输入缓冲区为:
123abc
其中1
、2
、3
都匹配成功,遇到a
时匹配失败,于是连续读取123
,并依照%d
的转换规格(将数据视为有符号十进制整数,进而以有符号整型的存储方式转换为补码)进行转换,再将产生的二进制数存储在以scanf()
括号内地址参数
为首地址的内存空间中。
(3)当占位符为%f
或%lf
时,scanf("%f",地址)
会连续读取匹配成功的字符(包括第一个小数点符号'.'
),直到遇见匹配不成功的字符,例如:
标准输入缓冲区为:
3.14.abc
其中会逐个匹配3
、.
、1
、4
都匹配成功,遇到第二个.
时匹配失败,于是连续读取3.14
,并依照%f
或%lf
的转换规格进行转换,再将产生的二进制数存储在以scanf()
括号内地址参数
为首地址的内存空间中。
这里要注意:
若占位符为%f
,则将数据视为十进制有符号小数,并以IEEE754中的单精度
存储法则,即转化为4字节二进制数据进行存储,因此scanf()
括号内地址参数
为首地址的内存空间要有4字节。
若占位符为%lf
,则将数据视为十进制有符号小数,并以IEEE754中的双精度
存储法则,即转化为8字节二进制数据进行存储,因此scanf()
括号内地址参数
为首地址的内存空间要有8字节。
因此不能以一个float
类型的变量去接收一个以%lf
占位符来输入的小数:
float f = 0;
scanf("%lf",&f);
因为%lf
会将数据转化为8字节长度,在放入内存时是从f
变量的首地址往后放8字节,但是用于接收的变量f
的量级为4字节,f
的数据范围只有从首地址往后4字节的区域,故而在输出f
时,另外4字节的数据是访问不到的。
同样:
double d;
scanf("%f",&d);
%f
会将匹配读取的数据转化为4字节二进制数据,并将数据放入d
的首地址往后4字节的内存空间中,但是double
型数据的量级为8字节,在访问d
时是访问其首地址往后8字节的内容,而以上情况只有4字节是自己传入的,另外4字节是自己未知的(可能是脏数据)。
即使另外4字节全为0,d是以IEEE754
中单精度浮点数的编码方式由十进制转化为二进制的,但是在输出时却是以IEEE754
中双精度浮点数的编码方式逆向将二进制转化为十进制,那么数据在转化过程就会发生紊乱,导致的最终结果也是错误的。
故而有以下结论:
%lf
转化的数据只能由double
类型的数据接收;
%f
转化的数据只能由float
类型的数据接收。
但float
、double
型数据输出时用%f
、%lf
都可以。
(4)当占位符为%c
时,scanf()
只会匹配并读取一个字符,但是无论这个字符是什么,它都会扫描成功并读取,并将其以%c的规格转化为二进制数存储在内存空间中。因此,%c是最特殊的一个占位符,一个%c只会匹配一个字符,它会匹配成功并读取任何字符,除非标准输入缓冲区为空。
(5)当占位符为%s
时,scanf()
会连续匹配所有的非空白字符,直到遇见空白字符,并且会读取遇见的第一个空白字符以前所有的非空白字符,不会读取空白字符,在读取成功后还会在末尾自动补上终止字符’\0’。
(5)标准输入缓冲区中被成功匹配的字符在成功读取后会被清除,而下一次的匹配从上一次未匹配成功的字符开始。
(6)除了%c
以外的占位符都具有清除前导空白字符的作用。空白字符有空格、制表符、换行符等,当这几个占位符进行匹配时,若标准输入缓冲区的开头有一个或多个连续空白字符,则会将其全部清空,并从第一个非空白字符开始匹配。
但如果是%c
,那即使是空白字符它也会匹配。
(7)scanf(" ",地址)
函数的双引号里是格式字符串,格式字符串里不止有上述说的占位符,也可以有其他字符,例如:'a'
,'b'
,'空格'
,如果有这些字符,那这些字符也会在标准输入缓冲区里发生匹配,并且只有在匹配到一致的字符时才算匹配成功。
6、完全不匹配的情况
有如下情况:
int a = 0;
int b = 0;
char c = 0;
scanf("%d%d%c",&a, &b, &c);
但是标准输入缓冲区为:
abc
第一个%d
匹配整数失败,则不会发生读取,因此a
保持原值,并且结束本占位符的匹配。
轮到下一个占位符%d进行匹配,依然匹配失败,依然不会发生读取,且b
保持原值,并且结束本占位符的匹配。
轮到下一个占位符%c进行匹配,匹配成功,发生读取,c
的值被修改。
总结出的法则是:若占位符发生完全不匹配的情况,则不会读取数据(故预备传值的地址空间依然保持原值),并结束本占位符的匹配,开始下一个占位符的匹配,直到遇见成功匹配的占位符。
scanf()
函数的返回值就是格式字符串中匹配成功的占位符个数。