1.缓冲区:
键盘(标准输入)->缓冲区->内存
2.scanf的执行逻辑:
(1)sizof依照输入的顺序依次读取变量:
a.依据打印类型的不同来判断是否从缓冲区读取数据
b.依照输入格式来判断,例:
scanf("=+%c",&a)
在输入时需要 =+(数据)
c.碰到不符合输入格式的数据,会跳过之后的数据
d.scanf和阻塞:
如果缓冲区无数据,scanf会等待输入数据,即阻塞(IO),反正 NIO(Non-Blocking IO)
3.常见问题:
(1)scanf和\n:
scanf("%d\n",&a);
a.问题:在输入第一个数据之后,编译器提示输入第二个数据,输入后发现a被赋予的是第一个值
b.原因:2.(b)和2.(d):
回车符代表\r和\n(好像是,没找到准确回答),再输入第一个数据之后,再按回车,刚好符合scanf的输入格式,即清空了缓冲区,接着发生了阻塞,所以此现象会发生在任何类型
c.其他:该问题会联想到另一现象"整形,字符串,浮点型会忽略前导空白符,而char类型不会",区别于此问题,在于该问题是scanf的输入格式契合:
(1)另一现象:除char类型外,在输入操作中,首次输入空白符,会一直提示再次输入,而char:
(2):前导空白符:从字符串的开头到第一个非空白符(回车符,制表符,空格符等)
(2):scanf的非法输入和循环:
a.原因:对于上图,scanf要求读取到十进制的整形,而标准输入为 ` ,所以scanf读取到零个数据,返回0,并且缓冲区中第一次输入的 ` 仍然存在,所以每一次循环都不会发生阻塞,每一次都如此循环
b.解决方法:
(1)用 flush(stdin) 或 rewind(stdin):
用上述两个函数来清楚缓冲区(全部清除)
flush(stdin)在vs2015之后的vs版本中不可用,可用rewind(stdin)代替,或者使用getchar(只能接受一个字符)
getchar:
(2)用scanf("%*[]"):
(1)*代表不赋值,^代表跳过,[]为集合,第一个scanf的输入格式带来的效果:会清除缓冲区内非数字,然后第二个scanf可以正常输入,达到某些情况下本只想要获得数字而意外输入非法字符带来的错误(如用程序计算金额)
并且:该输入格式读取的是整个字符串,所以应对以下输入格式也可以:
(2)
scanf("%[a-zA-Z]"),表示除了二十六个字母的大小写之外其他数据全部忽略
scanf("%n[]")n代表至多读取n个字符
scanf("%*[^\n]")表示除换行符,读入全部字符
scanf("%*[^\n]%c"),%c会匹配并储存一个字符,可以起到跳过行尾换行符的作用(个人理解是%c于的格式相对应)
(3)
在字符串的输入中,碰到空白符也影响输入,上图若改为scanf(%s),会导致数组arr1的长度始终为0