跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C/C++ 输入输出实战:OJ 场景与性能优化

C/C++ 输入输出处理涉及 OJ 常见模式、字符串读取技巧及流对象性能差异。文章涵盖单组与多组测试用例的处理方法,包括已知组数、未知组数及特殊值结束等场景。重点讲解了含空格字符串的读取方式,以及整数与字符串解析的区别。核心部分对比了 scanf/printf 与 cin/cout 在格式控制和性能上的不同,指出大数据量下 cin/cout 默认同步带来的性能损耗,并给出 ios::sync_with_stdio(false) 和 cin.tie(0) 的优化方案,帮助开发者在算法竞赛中避免超时。

SecGuard发布于 2026/3/24更新于 2026/9/884 浏览
C/C++ 输入输出实战:OJ 场景与性能优化

前言

在编程中,输入输出(I/O)是交互的基础。C 和 C++ 提供了丰富的机制,从简单的 printf/scanf 到流式操作 cin/cout。看似简单,实则暗藏玄机。缓冲区问题、格式控制陷阱、性能瓶颈都可能成为调试的拦路虎。本文将针对这些常见问题逐一拆解。

1. OJ 题目输入情况汇总

在竞赛环境中,输入场景通常分为以下几类。结合具体题目来看会更直观。

1.1 单组测试用例

例如计算 (a+b)/c 的值。

#include <iostream>
using namespace std;
int main() {
    int a, b, c;
    cin >> a >> b >> c;
    cout << (a + b) / c << endl;
    return 0;
}

再比如'与 7 无关的数'。思路是先找出与 7 相关的数取反。条件包括被 7 整除、个位是 7、十位是 7。

#include <iostream>
using namespace std;
int main() {
    int n;
    cin >> n;
    int i = 1, sum = 0;
    while (i <= n) {
        if (i % 7 != 0 && i % 10 != 7 && i / 10 != 7) {
            sum += (i * i);
        }
        i++;
    }
    cout << sum << endl;
    return 0;
}

1.2 多组测试用例

1.2.1 测试数据组数已知

如果题目明确告诉你有 N 组数据,直接循环 N 次即可。

#include <iostream>
using namespace std;
int main() {
    int n; // 表示数据组数
    cin >> n;
    int a, b;
    while (n--) {
        cin >> a >> b;
        cout << a + b << endl;
    }
    return 0;
}

对于斐波那契数列,如果范围限制在 30 以内,预处理数组比每次递归或循环更高效。

#include <iostream>
using namespace std;
int main() {
    int n, a, i;
    int ret[35] = {0, 1, 1};
    for (i = 3; i < 30; i++) {
        ret[i] = ret[i - 1] + ret[i - 2];
    }
    cin >> n;
    while (n--) {
        cin >> a;
        cout << ret[a] << endl;
    }
    return 0;
}

还有一种常见写法是处理 q 次询问,用 while(q--) 包裹单组逻辑。注意字符串下标通常从 0 开始,但题目可能从 1 开始计数,需调整。

1.2.2 测试数据组未知

当不知道有多少组数据时,利用 cin 的返回值特性。

#include <iostream>
using namespace std;
int main() {
    int a, b;
    while (cin >> a >> b) {
        cout << a + b << endl;
    }
    return 0;
}

原理是 cin >> a >> b 返回流对象引用,成功读取转为 true,遇到 EOF 或错误转为 false。

1.2.3 特殊值结束测试数据

有时以特定值(如 0 0)作为结束标志。

#include <iostream>
using namespace std;
int main() {
    int a = 0, b = 0;
    while (cin >> a >> b, a && b) {
        cout << a + b << endl;
    }
    return 0;
}

这里利用了逗号表达式,整体结果取决于最后一个表达式。

2. 输入时特殊技巧

2.1 含空格字符串的特殊处理方式

读取带空格的字符串,可以用 fgets、scanf、getchar 或 getline。但如果只需按单词处理,直接用 cin >> s 自动跳过空格更方便。 例如统计数字字符个数,可以一次性读入整个行分析,也可以逐个单词读入。

// 法一:读取整行
#include <iostream>
#include <string>
using namespace std;
int main() {
    string s;
    getline(cin, s);
    int ret = 0;
    for (auto ch : s) {
        if (ch >= '0' && ch <= '9') ret++;
    }
    cout << ret << endl;
    return 0;
}
// 法二:按单词处理
#include <iostream>
#include <string>
using namespace std;
int main() {
    string s;
    int cnt = 0;
    while (cin >> s) {
        for (auto c : s) {
            if (c >= '0' && c <= '9') cnt++;
        }
    }
    cout << cnt << endl;
    return 0;
}

判断字符类型时,使用 isdigit(ch) 或 isalpha(ch) 比手动比较 ASCII 更简洁。

2.2 数字的特殊处理方式

输入的数字既可以是整数也可以是字符串。根据需求选择解析方式。 如果是奇偶转换,可以直接对整数取模,也可以当作字符串处理 ASCII 码。

// 法一:当做整数读取
#include <iostream>
#include <cmath>
using namespace std;
int main() {
    int n;
    int i = 0, ret = 0;
    cin >> n;
    while (n) {
        if (n % 10 % 2 == 1) ret += pow(10, i);
        n /= 10;
        i++;
    }
    cout << ret << endl;
    return 0;
}
// 法二:当做字符串处理
#include <iostream>
#include <string>
using namespace std;
int main() {
    string s;
    cin >> s;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] % 2) s[i] = '1';
        else s[i] = '0';
    }
    cout << stoi(s) << endl;
    return 0;
}

stoi 是 C++11 引入的函数,用于将字符串转换为整数。

3. scanf/printf 和 cin/cout 的对比

scanf/printf 是 C 语言标准库,cin/cout 是 C++ 流对象。各有优劣。

3.1 格式控制差异

scanf/printf 需要手动指定格式,容易出错但精确;cin/cout 自动识别类型,更安全易用。但在复杂格式输出时,printf 更灵活。

#include <cstdio>
#include <iostream>
using namespace std;
int main() {
    float a = 3.50;
    double d = 16.50;
    cout << "cout: " << a << " " << d << endl;
    printf("printf: %f %lf\n", a, d);
    return 0;
}

cout 默认忽略多余 0,printf 默认打印 6 位小数。

3.2 性能差异

大数据量下,scanf/printf 通常更快。cin/cout 默认与 C 标准库同步,且绑定刷新,导致开销增加。 优化方案是在程序开头加入:

ios::sync_with_stdio(false);
cin.tie(0);

这能取消同步和绑定,大幅提升速度。

结语

掌握输入输出的底层机制,才能写出健壮高效的代码。无论是缓冲策略还是格式控制,每个细节都影响最终表现。

目录

  1. 前言
  2. 1. OJ 题目输入情况汇总
  3. 1.1 单组测试用例
  4. 1.2 多组测试用例
  5. 1.2.1 测试数据组数已知
  6. 1.2.2 测试数据组未知
  7. 1.2.3 特殊值结束测试数据
  8. 2. 输入时特殊技巧
  9. 2.1 含空格字符串的特殊处理方式
  10. 2.2 数字的特殊处理方式
  11. 3. scanf/printf 和 cin/cout 的对比
  12. 3.1 格式控制差异
  13. 3.2 性能差异
  14. 结语

更多推荐文章

查看全部
  • WebSocket 核心原理与前后端实战用法详解
  • Leaflet 结合 SpringBoot 实现地图点击获取当地时间
  • Java 核心技术面试指南:基础、JVM 与框架实战
  • 数据结构与算法:查找算法核心原理及实战题目解析
  • DeepSeek 与通义万相结合制作 AI 视频实战指南
  • Apache IoTDB 时序数据管理:写入、存储与查询优化
  • Java static 关键字入门:静态变量特点与基础实战
  • 利用文心一言构建稳定调用的智能体工作流提示词
  • AI绘画电商产品提示词撰写指南
  • Git 配置与使用详解
  • C++ 基础概念详解:命名空间、引用与函数重载
  • Python Requests 爬虫库核心功能与生态对比
  • 电子招标采购商城系统优化传统采购与数字化升级
  • Python 爬虫实战:12306 票价信息与区间价格分析
  • VR 音游音符轨道系统开发实录与原理解析
  • HTML 前端接入大模型 API:OpenAI 兼容接口快速部署指南
  • OpenClaw 集成百度网页搜索技能指南
  • 文心一言 4.5 评测与本地部署指南:开源大模型的中文能力实测
  • Linux 进程替换原理:从 fork 到 exec 详解
  • 基于 Netty 构建高性能 HTTP 服务器

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online