作者twotwoone (我不配)
看板C_and_CPP
标题Re: [问题] C用法的限制???
时间Fri Nov 20 22:36:06 2009
回覆上篇推文
1F:推 VictorTom:其实小弟我不懂的是, Enter塞回去给下一个读的状况, 那11/20 20:43
2F:→ VictorTom:我後面如果都是读数字的scanf为什麽就不会Enter塞住??11/20 20:44
3F:→ VictorTom:应该有些人有经验, 要读数字时喂英文字, 就塞爆了@_@"11/20 20:44
scanf() 每次执行後,会先去输入缓冲区 (input buffer) 找看看有没有内容
如果是空的(内含透明字视为空),就会等候使用者的按键输入,
直到 enter 被按下才结束。
这个 enter 在输入缓冲区会纪录为 '\n' 即 0xa (是 Windows;Linux 未测)。
今天假设使用者输入『123 456』然後按下 enter,则输入缓冲区值为『123 456\n』。
scanf 会从缓冲区的第一个字元开始,跟其参数1传来的字串值做比对 (match),
只有在 match 时,才从缓冲区删除该字串。
换言之,比对规则不管是 scanf("123"); 或 scanf("%d", &number1);
都会跟缓冲区里的『123』做比对成功,然後删掉比对成功的字串值,
使得新的缓冲区变成『 456\n』。
再接着执行 scanf("%d", &number2); 时,同样会从第一个字元「半形空白」开始比对。
而「半形空白、tab、enter」被归类为透明字元,处理时一律会被忽略。
因此 number2 能抓到 456 这个值。
今天如果把缓冲区第一个字元,由半形空白换成全形空白,
则跟整数做比对的结果会是失败的。
因此 number2 最终没有改变数值,输入缓冲区同样也没有变动,两者皆维持原状。
==
同理
int x=-1, y=-1;
scanf("%d", &x);
scanf("%d", &y);
第一次 scanf 执行时
假设使用者输入『123』还有『tab』还有『enter』,
即输入缓冲区为『123\t\n』。
结果是 123 比对成功,新的缓冲区为『\t\n』这两个透明字元。
第二次 scanf 执行时
之前的透明字元都被忽略,因此系统会再次等待使用者输入内容。
即使两次 scanf() 函数中间,放入一个 getchar(); 也不会改变结果,
这个 getchar() 会抓到 '\t' (0x9) 的值。
==
上一篇文章解决方法之一,就是把输入缓冲区的垃圾值冲掉 (flush)
可以这样做
char val;
do{
val = getchar();
}while(val != '\n');
执行完此回圈後,缓冲区内的 enter 就会被吃光光了。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 124.8.149.40
※ 编辑: twotwoone 来自: 124.8.149.40 (11/20 22:40)
润饰一下句子。
※ 编辑: twotwoone 来自: 124.8.149.40 (11/20 23:14)
4F:推 VictorTom:看来就是差在透明字的处理, 感谢221大....<(_ _)> 11/20 23:10
5F:→ VictorTom:其实有code能实际trace一遍的话就不会模糊到现在了Orz 11/20 23:12
6F:推 Eric30:推一个 解释的非常详细 :) 11/20 23:49
7F:推 ledia:去 google search 找 libc/stdio/vfscanf.c 11/21 00:14
8F:→ ledia:一些怪用法都是从里面找到的.... XD 11/21 00:14
9F:推 LPH66:补充 *scanf的参数只有 %c 不会略过透明字(whitespace) 11/21 02:39
10F:→ twotwoone:原来还有这个例外,感谢! 11/21 02:59
11F:推 ledia:啊 是 google code search .... orz 11/21 08:44
12F:嘘 Shauds: 01/09 13:32