为什么fmt.Scanf中%d后的换行被消费,%c后的换行未被消费?
Go fmt.Scanf 输入匹配问题解答
问题1:为何r2取到的是换行符,而r1取到的是字符a?
核心原因是fmt.Scanf的动词规则和Windows平台交互式标准输入的行缓冲机制共同作用的结果:
fmt.Scanf的基础匹配规则:- 除
%c、%n、%[三个动词外,其余所有动词都会自动跳过输入中有效数据前的所有空白字符(空格、制表符、换行符等),再读取匹配内容。 %c不会跳过任何前导空白,会直接读取输入指针当前指向的下一个rune。
- 除
- 你的输入序列
1 回车 a 回车在Windows控制台行缓冲模式下,按下回车提交输入时,系统会将换行符作为行结束标记处理,不会送入应用层的输入缓冲区。因此第一次Scanf("%d")读取数字1之后,输入指针直接指向后续输入的字符a,第二次%c读取到a(ASCII 97),第三次%c读取到输入a之后按下的换行符(ASCII 10)。
问题2:是否是%d后的换行符不匹配导致的?
不是,该现象和匹配失败无关。
官方注释里提到的「输入中的换行必须与格式中的换行匹配」,指的是格式串中显式写了\n字符的场景,此时输入对应位置必须是换行符才能匹配成功。你的格式串%d中没有显式声明换行符,因此不存在「换行不匹配」的问题。
你感知到的「%d后的换行被自动消费」是错觉:如果%d之后调用的是除%c外的其他动词,该动词会自动跳过前导的所有空白字符,看起来就像换行被消费了,但本质是后续动词的空白跳过逻辑,和%d本身无关。
问题3:用buffer作为输入源时输出和标准输入不一致的原因?
差异来自两种输入源的行为不同:
- 使用Buffer模拟输入时,你是将完整的字节序列(包括所有换行符)一次性写入缓存,所有字符都会保留在输入流中等待读取。此时第一次
%d读取数字1之后,输入指针停留在第一个换行符的位置,第二次%c会直接读取到这个换行符,和交互式输入的结果自然不同。 - Windows控制台的交互式标准输入存在行缓冲处理逻辑,换行符会被作为行提交的标记被系统层过滤,不会进入应用层的输入缓冲区,因此不会被
%c读取到。
内容的提问来源于stack exchange,提问作者syang
相关产品推荐
相关产品推荐

