news 2026/10/12 3:06:04

快读快写学习笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
快读快写学习笔记

1. 前置准备

所有代码依赖以下头文件,建议统一包含:

  • <cstdio>:提供getchar()、putchar()、fread()、fwrite()。
  • <iostream>:提供cin、cout。
  • <cctype>:提供isspace()。

2. 基础 I/O 优化:基于cin和cout

2.1. 优化步骤

  1. 关闭流同步:
  • 实现:通过ios::sync_with_stdio(false)关闭 C++ 和 C 输入输出流的同步。
  • 解释:为了确保混用 C++ 的cin/cout和 C 的printf/scanf不会产生 I/O 混乱,C++ 和 C 的两种流之间进行了同步。这提高了兼容性,但是产生了大常数。关闭流同步之后就不要同时使用cin和scanf,也不要同时使用cout和printf,否则会造成 I/O 混乱。但可以同时使用cin和printf,也可以同时使用scanf和cout。
  1. 解除绑定:
  • 实现:通过cin.tie(nullptr)解除cin与cout的绑定。
  • 解释:在 C++ 中,cin默认绑定的是&cout,这意味着每次读入都会调用flush()。可以用cin.tie(nullptr)函数解除这种绑定。
  1. 针对endl的优化:
  • 实现:用'\n'替换endl。
  • 解释:endl的作用是换行并刷新缓冲区,相当于cout<<'\n'<<flush。而刷新缓冲区会带来一定开销。

其中前两步一般合称「关流」。后文会沿用这个称呼。

2.2. 代码实现

以下两种写法是等价的:

// 写法1:链式调用cin.tie(0)->sync_with_stdio(0);
// 写法2:分步调用ios::sync_with_stdio(0);cin.tie(0);

可以这样将所有endl替换为'\n':

// 注意:该宏需在包含<iostream>之后定义,避免与std::endl声明冲突#defineendl'\n'

3. 进阶优化:快读

3.1. 普通快读:基于getchar()

通过getchar()函数逐字符读取,手动解析整数或字符串。

voidread(int&x){// 读整数(支持负数)intc,f=1;while((c=getchar())<'0'||c>'9')if(c=='-')f=-1;for(x=c^48;(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^48));x*=f;}voidread(char&c){// 读一个非空字符while(isspace(c=getchar()));}intread(chars[]){// 读一个字符串,到空格/EOF为止,返回长度intlen=0;charc;while(isspace(c=getchar()));dos[len++]=c;while(!isspace(c=getchar())&&c!=EOF);s[len]='\0';// 补字符串结束符returnlen;}intgetline(chars[]){// 读一行字符串,返回长度intlen=0;charc;while((c=getchar())!='\n'&&c!=EOF)s[len++]=c;s[len]='\0';// 补字符串结束符returnlen;}

3.2. 缓冲区快读:基于fread()

getchar()每次从系统读取 1 个字符,频繁调用系统接口,开销大。fread()一次性读取一整块数据到自定义缓冲区,后续从缓冲区取字符。这样可以减少系统调用次数,速度通常可以提升 5~10 倍。

缓冲区一般大小设为 1MB 左右,即2202^{20}220字节,这样既不会占太大空间,不会刷新太多次缓冲区。

由于fread可以一次整块读入,因此速度比getchar快多了。

charin[1<<20],*p1,*p2;inlinechargc(){// 从缓冲区读1个字符,空则补充returnp1==p2&&(p2=(p1=in)+fread(in,1,1<<20,stdin))==in?EOF:*p1++;}

加上这段代码,然后用gc()替换掉所有getchar()就可以了。

4. 进阶优化:快写

4.1. 普通快写:基于putchar()

通过putchar()函数逐字符输出。

voidwrite(intx){// 写整数(支持负数)if(x<0)putchar('-'),x=-x;x<10?putchar(x|48):(write(x/10),putchar(x%10|48));}voidwrite(chars[],intlen){// 写字符串,指定长度for(inti=0;i<len;++i)putchar(s[i]);}voidwrite(chars[]){// 写字符串,直到'\0'为止for(inti=0;s[i];++i)putchar(s[i]);}

4.2. 缓冲区快写:基于fwrite()

和缓冲区快读差不多,自定义一个缓冲区,每次写一个字符到缓冲区,满了就刷新缓冲区,通过fwrite()一次性将整个缓冲区里的内容输出。

加上如下代码,再用pc()替换掉所有putchar()就可以了。

charout[1<<20],*p3=out;inlinevoidpc(charc){// 向缓冲区写1个字符,满则刷新if(p3-out==1<<20)fwrite(out,1,1<<20,stdout),p3=out;*p3++=c;}

但是程序结束时,缓冲区里可能还有东西,因此我们必须在结束前清空缓冲区。这一步千万不要忘!

fwrite(out,1,p3-out,stdout);

5. 工程化实现:I/O 类封装

5.1. 封装的核心目的

  • 自动管理缓冲区:析构函数自动调用fwrite()刷新输出缓冲区,避免忘记刷新。
  • 统一接口:将快读和快写整合到同一个类中,使用时直接调用io.函数名(参数)即可,无需再关注底层实现,适合作为缺省源使用。

5.2. 代码实现

classIO{#defineSIZE1<<20private:charin[SIZE],out[SIZE],*p1,*p2,*p3;public:IO():p1(in),p2(in),p3(out){}~IO(){fwrite(out,1,p3-out,stdout);}inlinechargc(){// 从缓冲区读1个字符,空则补充returnp1==p2&&(p2=(p1=in)+fread(in,1,SIZE,stdin))==in?EOF:*p1++;}inlinevoidpc(charc){// 向缓冲区写1个字符,满则刷新if(p3-out==SIZE)fwrite(out,1,SIZE,stdout),p3=out;*p3++=c;}voidread(int&x){// 读整数(支持负数)intc,f=1;while((c=gc())<'0'||c>'9')if(c=='-')f=-1;for(x=c^48;(c=gc())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^48));x*=f;}voidread(char&c){// 读一个非空字符while(isspace(c=gc()));}intread(chars[]){// 读一个字符串,到空格/EOF为止,返回长度intlen=0;charc;while(isspace(c=gc()));dos[len++]=c;while(!isspace(c=gc())&&c!=EOF);s[len]='\0';// 补字符串结束符returnlen;}intgetline(chars[]){// 读一行字符串,返回长度intlen=0;charc;while((c=gc())!='\n'&&c!=EOF)s[len++]=c;s[len]='\0';// 补字符串结束符returnlen;}voidwrite(intx){// 写整数(支持负数)if(x<0)pc('-'),x=-x;x<10?pc(x|48):(write(x/10),pc(x%10|48));}voidwrite(chars[],intlen){// 写字符串,指定长度for(inti=0;i<len;++i)pc(s[i]);}voidwrite(chars[]){// 写字符串,直到'\0'为止for(inti=0;s[i];++i)pc(s[i]);}#undefSIZE}io;// 全局实例化,无需重复创建对象

6. 关键避坑指南

  1. 混用不同 I/O 方式:
    • 关流后不能混用cin和scanf,也不能混用cout和printf。
    • 缓冲区快读与getchar()不可混用,缓冲区快写和putchar()也不能混用。
  2. 缓冲区快写忘记刷新:非封装版本需在程序结束前调用fwrite(out,1,p3-out,stdout),否则缓冲区剩余数据不会输出。
  3. 整数快读快写处理边界值:处理INT_MIN即−2147483648-2147483648−2147483648时会溢出,若需支持要开long long。

7. 性能对比与选型建议

I/O 方式速度排序优点缺点适用场景
缓冲区快读快写1速度极致,适合大数据代码长,需封装,不支持复杂类型(如浮点数)输入超大,高频 I/O 的题目
普通快读快写2代码短,速度快不支持复杂类型(如浮点数)输入较大,需要卡常的题目
关流cin/cout3代码超短兼容性差一般题目
scanf/printf4适合输出格式串格式控制符复杂,速度较慢一般题目
不关流cin/cout5兼容性好速度极慢极小数据量的题目,调试输出

注:若需支持浮点数(如double),需扩展快读快写函数,手动解析小数点前后数字。因浮点数 I/O 场景较少,通常含有浮点数的题目数据量也不会太大,本文暂不展开,可根据需求自行扩展。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/12 3:06:01

基于RK3588的多模态婴儿智能监测系统设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/12 3:05:23

LBM格子玻尔兹曼方法入门:用NumPy手写D2Q9求解器

简介&#xff1a;本资源是一套基于格子Boltzmann方法&#xff08;LBM&#xff09;的流体流动数值模拟开源实现&#xff0c;面向计算流体力学初学者、高校科研人员及C高性能仿真开发者&#xff0c;用于学习LBM核心原理与工程实践。代码以C编写&#xff0c;依托OpenLatticeBoltzm…

作者头像 李华
网站建设 2026/10/12 3:05:15

用Python构建电报发卡机器人:库存、订单与支付对账实践

简介&#xff1a;这是基于Python开发的开源电报发卡机器人源码包&#xff0c;面向需要在Telegram中实现卡密自动发货、订单管理与易支付收款对接的开发者或小商家&#xff0c;可快速搭建一套轻量发卡系统。程序在Python 3.6.7下测试通过&#xff0c;数据层采用sqlite3存储&…

作者头像 李华
网站建设 2026/10/12 3:04:18

跨平台游戏兼容:技术实战与体验优化

同一款游戏,在高端手机上流畅运行,在低端安卓机上却频繁闪退;电脑上鼠标操作顺手,换成手柄后却连背包都难以使用。 这说明: 跨平台兼容,不只是“能安装、能启动”,而是让游戏在不同设备上都能正确运行、合理交互,并保持可接受的体验。 下面以一款虚构的多人动作游戏为…

作者头像 李华
网站建设 2026/10/12 3:04:07

VC++高仿360杀毒:扫描引擎与特征库实战

简介&#xff1a;这是一份基于VC实现的360杀毒高仿项目源码&#xff0c;面向具备C基础、希望深入Windows桌面开发与安全软件架构的学习者。项目以MFC与SkinUI界面库搭建皮肤化窗口&#xff0c;通过XML布局文件实现界面与业务逻辑解耦&#xff0c;并模拟病毒扫描、隔离清除、多线…

作者头像 李华