【转载】关于C/C++ stdin缓冲区以及对字符输入的一些经验和心得

 

  在使用C/C++编写控制台应用或acm竞赛的时候,I/O方式无非是标准输入输出,特别是acm竞赛,就本人来讲,由C语言入门,输入方式还只会scanf,自从学了C++,便深深地被 cin/cout输入输出流的简洁用法所吸引,相信有这种感受的不止我一我的。 
  因此很长一段时间,平常的训练和各类线上比赛,再也没有使用过scanf,反手一个cin感受很炫酷。然而好景不长,一次bestcoder的常规线上赛,前期发挥稳定,手感至关好,1001和1002快而准地ac,1003也很快来了思路(两年前的事情了,细节什么的早忘了),咔咔咔敲完代码提交ac,最后剩下充足的时间攻克1004,虽然到结束也没作出来,可是3题铁定涨分啊…… 
  然而终判的结果让我大吃一鲸,T!L!E!,竟然超时,百思不得其解之时(其实以前知道cin效率低,可是用着太顺手了就没在乎),想到了会不会是数据太多?而后等着终判结束题目开放,抱着试一试的心态,把cin改为了scanf,而后……竟然……秒过…… 
  而后网上查阅资料(只说输入,输出大同小异),cin慢的缘由不少,其中很重要的一点是为了使cinscanf能够兼容混合使用,cin在内部实现的时候会同步输入缓冲区,也就是说,输入流会时刻与输入缓冲保持同步,这是一个很耗时的操做,因此就致使了在大量输入数据的时候,cin会比scanf慢不少,能够说,这个慢,是数量级上的差别。 
  若是你能够保证程序中不会出现标准输入与流输入混用的状况,能够在程序开始时使用ios::sync_with_stdio(false);关闭同步来提升速度,可是在大量数据面前输入速度仍显得乏力,相比scanf仍是慢了一些(上面说的1003题我用cin关同步仍是超时,只有scanf能过),我的认为缘由在于对输入流对象的封装和>>这个符号的运算符重载致使执行时间变慢。 
  因此从那之后,在acm生涯里再也没有使用过cin……硬生生地改回了scanf的习惯。简洁和效率总要舍弃一个,对于算法竞赛来讲,效率才是关键吧……ios


  说了这么多cin与scanf的速度比较,接下来重点说一下scanf,用法没必要多说,结合多年来竞赛经验,介绍一下格式符%c与其余格式符的区别和特定使用场景的注意事项。算法

  %c是一个很奇葩的设定,单独读入一个字符,包括不可见的控制字符(换行等),而其余格式化符号(如%d %lld %f %lf %s等)会在读入未完成时将换行符、空格、制表符等空白字符通通舍弃忽略,直到读到了足够的数据或遇到文件结尾才结束。咱们平时控制台输入时一般按行输入,也就是输入数据后要敲击回车才能被读取,这样就致使了换行符在%c与其余格式符号并存的程序中出现各类问题,例如没法得到理想输入数据,字符串错误错误致使程序崩溃等。优化

 

总结下来就是:指针

①scanf至少要比cin快一倍左右code

②cin慢的缘由:默认状况,cin与stdin老是保持同步的,也就是说这两种方法能够混用,而没必要担忧文件指针混乱,同时cout和stdout也同样,二者混用不会输出顺序错乱。正由于这个兼容性的特性,致使cin有许多额外的开销。(解决:只需一个语句std::ios::sync_with_stdio(false);,这样就能够取消cin于stdin的同步了,此时的cin就与scanf差很少了)对象

③cin、cout是在编译期间就决定了读入变量的类型。而scanf()是在运行期决定的,编译器没法优化,并且还要识别字符串。理论上scanf比cin要慢不少,实际上快的缘由是不少编译器对cin、cout的处理过于保守。ci

④同牛人建议,Acmer 尽可能用scanf,printf来进行输入输出吧....字符串