OI 中输入输出那些事

本文是为了教一个小学弟写的,为了文章完整性我全面总结了一些 OI 中经常用到的哪些输入输出技巧以及注意事项

std::cinstd::cout

我相信你的第一行 C++ 代码一定是下面这个:

#include <bits/stdc++.h>using namespace std;int main() {cout << "Hello, world!" << endl;return 0;
}

接下来你一定还学过 cout 用于输入。但是这里有两个小问题,第一是在 CCF 举办的 NOI 赛事中,使用 using namespace std 有概率导致你的程序在 Windows 平台正常运行但在测评环境出错;第二是 endl 会强制刷新缓冲区,导致输出效率变慢。所以我更推荐你使用下面的写法:

#include <bits/stdc++.h>int main() {std::cout << "Hello, world!" << '\n';return 0;
}

顺带讲一下 using namespace std 的作用吧。这行代码表示“使用 std 命名空间”。如果你不理解,那么你只需要记住,使用这行代码可能会导致你的一些变量名与内置的一些符号产生冲突,经典的案例就是 nexty0 等。删除这一行代码之后,你无脑的在调用内置函数之前加上 std:: 前缀即可。特别的,如果某个函数添加 std:: 后出现问题但不添加就能正常运行,那你无脑不添加就好了,这往往是由于某些 C 语言的特性与 C++ 冲突而编译器不能很好地处理导致的。

std::getline

另外值得一提的是,你可以使用 std::getline 读取一整行输入:

std::string s;
std::getline(std::cin, s);

另外还有一个 getline 方法可用于输入一行内容到 char[]

char s[256];
std::cin.getline(s, 256);

printfscanf

想必你一定也见过这两个函数。敏锐的你也许会注意到,这两个函数我并没有添加 std::,这是由于这两个函数源自 C 语言,因此也被称为 C 风格输入输出;相应地,std::cinstd::cout 被称为 C++ 风格的。你也许经常听到有人说这 C 风格的输入输出比 C++ 风格的更快,在一般情况下确实如此。

顺带一提的是 C 风格输入输出的格式化字符串,这里给出一个列表用于快速查询:

整数类型

  • 有符号整数

    • %d%i: 十进制整数
    • %ld%li: 长整型(long int
    • %lld%lli: 长长整型(long long int
  • 无符号整数

    • %u: 无符号十进制整数(unsigned int
    • %lu: 无符号长整型(unsigned long int
    • %llu: 无符号长长整型(unsigned long long int
  • 八进制

    • %o: 八进制整数(默认为int
    • %lo: 无符号长整型的八进制表示(unsigned long int
    • %llo: 无符号长长整型的八进制表示(unsigned long long int
  • 十六进制

    • %x%X: 十六进制整数(小写或大写字母)(默认为int
    • %lx%lX: 无符号长整型的十六进制表示(unsigned long int
    • %llx%llX: 无符号长长整型的十六进制表示(unsigned long long int

浮点数类型

  • 小数形式

    • %f: 小数形式的浮点数(默认为double
    • %lf: 双精度浮点数(double
    • %Lf: 长双精度浮点数(long double
  • 科学计数法

    • %e%E: 科学计数法表示的浮点数(小写或大写字母'e')(默认为double
    • %le%lE: 双精度浮点数的科学计数法表示(double
    • %Le%LE: 长双精度浮点数的科学计数法表示(long double
  • 自动选择格式

    • %g%G: 根据数值大小自动选择%f%e(小写或大写字母)(默认为double
    • %lg%lG: 双精度浮点数的自动选择格式(double
    • %Lg%LG: 长双精度浮点数的自动选择格式(long double

字符和字符串

  • %c: 单个字符
  • %s: 字符串

指针

  • %p: 指针地址

其他

  • %n: 将当前已读取或写入的字符数量存入指向的整型变量中
  • %%: 输出百分号本身

精度和宽度控制

  • 宽度控制

    • %5d: 最少占用5个字符宽度,不足部分用空格填充(左对齐时加-,如%-5d
    • %05d: 最少占用5个字符宽度,不足部分用0填充
  • 精度控制

    • %.2f: 小数点后保留2位小数
    • %.3e: 科学计数法表示,小数点后保留3位小数
    • %.4g: 自动选择格式,小数点后最多保留4位有效数字

事实上,这样的输入输出方式虽然有不少优点,但是也有不少弊端,因此我不是很推荐这种写法。

同步流对速度的影响

前面提到,C 风格的输入输出往往比 C++ 的更快,这是由于默认情况下 C++ 的输入输入输出需要与 C 风格的同步,借助于所谓同步流。我们可以通过关闭同步流解决这一问题:

std::cin.tie(nullptr)->sync_with_stdio(false);

只需要在 main 函数第一行添加上这句代码就可以了,此时 C++ 风格的速度往往与 C 风格的相同甚至更优。需要注意的是,使用这行代码后,你最好不要再使用 C 风格的输入输出,否则极有可能因为没有同步而导致出 bug。

实际上,这行代码不仅关闭了同步流,还解除了 std::cinstd::cout 的绑定,也能在一定程度上提升速度。

奇技淫巧:快读快写

你也许还学过所谓快读快写,使用 getcharputchar 来优化输入输出,像下面这样¹:

int read() {int x = 0, w = 1;char ch = 0;while (ch < '0' || ch > '9') { // ch 不是数字时if (ch == '-') w = -1;     // 判断是否为负ch = getchar();            // 继续读入}while (ch >= '0' && ch <= '9') { // ch 是数字时x = x * 10 + (ch - '0');     // 将新读入的数字「加」在 x 的后面// x 是 int 类型,char 类型的 ch 和 '0' 会被自动转为其对应的// ASCII 码,相当于将 ch 转化为对应数字// 此处也可以使用 (x<<3)+(x<<1) 的写法来代替 x*10ch = getchar(); // 继续读入}return x * w; // 数字 * 正负号 = 实际数值
}void write(int x) {static int sta[35];int top = 0;do { sta[top++] = x % 10, x /= 10; } while (x);while (top) putchar(sta[--top] + 48); // 48 是 '0'
}

需要注意的是,putchargetchar 都是 C 风格的,因此与关闭同步流的 C++ 风格输入输出不兼容。

当然了,还有更多复杂的技巧,但是个人不推荐使用也不推荐了解。这是由于在输入输出上花费这么多时间和精力得不偿失,只有毒瘤题会折腾输入输出。

文件读写之 freopen

freopen 可用于重定向输入输出到指定文件,使用格式如下:

freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);

将这两行代码添加到 main 函数开头就可以了。

这也是一个 C 风格的函数,因此不建议使用。优点是可以通过注释或取消注释这两行代码快速实现文件读写与控制台输入输出的切换。

文件读写之 fopen

这种文件读写也是 C 风格的,请自行阅读示例代码:

FILE *in_file  = fopen("test.in", "r"),*out_file = fopen("test.out", "w");
int number;
// 从输入文件读取整数
fscanf(in_file, "%d", &number);
// 写入输出文件
fprintf(out_file, "%d", number);
// 关闭文件
fclose(in_file);
fclose(out_file);

在竞赛中没什么优势,不推荐使用。

C++ 风格文件流

全文的重头戏来了!使用 C++ 风格的文件流进行文件读写不仅可以获得极致的速度,还能拥有舒适便捷的编码体验。只需要在 main 函数开头使用下面的代码打开文件:

std::ifstream fin("test.in");
std::ofstream fout("test.in");

接下来就可以使用 finfout 替换 std::cinstd::cout 进行文件读写:

int n;
fin >> n;
fout << n << '\n'; // 仍然不推荐使用 `std::endl` 用于换行std::string str;
std::getline(fin, str);char s[256];
fin.getline(s, 256);

当然了,你还可以通过添加下面的代码对 std::cinstd::cout 重定向:

std::cin.rdbuf(fin.rdbuf());
std::cout.rdbuf(fout.rdbuf());
std::cin.tie(nullptr)->sync_with_stdio(false);

这样就可以照常使用 std::cinstd::cout 进行文件读写了。同时可以通过注释或取消注释这两行代码实现文件读写与控制台输入输出的切换。有测试表明这种方法是不使用奇技淫巧的前提下的普遍最优读写方式。

C++ 风格格式化输入输出

以下是C++中常用的输入输出格式化控制方法示例:

// 1. 浮点数精度控制
double pi = 3.1415926535;
std::cout << std::fixed << std::setprecision(2) << pi << "\n";  // 输出3.14
std::cout << std::scientific << pi << "\n";  // 输出3.14e+00// 2. 数值进制控制
int num = 255;
std::cout << std::hex << num << "\n";    // 输出ff
std::cout << std::oct << num << "\n";    // 输出377
std::cout << std::dec << num << "\n";    // 恢复十进制// 3. 宽度与填充
std::cout << std::setw(10) << std::setfill('*') << 123 << "\n";  // 输出*******123// 4. 对齐方式
std::cout << std::left << std::setw(10) << "Hello" << "\n";     // 左对齐
std::cout << std::right << std::setw(10) << "World" << "\n";    // 右对齐// 5. 其他常用格式
std::cout << std::boolalpha << true << "\n";    // 输出true(而非1)
std::cout << std::showpos << 42 << "\n";        // 输出+42
std::cout << std::uppercase << 3.14e2 << "\n";  // 输出3.14E+02// ========== 输入格式化 ==========
int year, month;
// 输入格式:YYYY/MM
std::cin >> year >> std::ws;  // 跳过空白字符
std::cin.ignore(1);           // 跳过分隔符'/'
std::cin >> month;// 恢复默认设置
std::cout.unsetf(std::ios::fixed | std::ios::scientific);
std::cout.precision(6);  // 恢复默认精度

常用格式化操作符对照表

操作符/函数 作用 示例效果
std::setprecision(n) 设置浮点数精度 3.1416 → 3.14
std::fixed 固定小数位显示 123.456 → 123.46
std::scientific 科学计数法显示 1234.5 → 1.2345e+03
std::hex/std::oct 十六进制/八进制显示 255 → ff / 377
std::setw(n) 设置字段宽度 123 → " 123"
std::setfill(c) 设置填充字符 123 → ****123
std::left/std::right 左对齐/右对齐 "Hello" → "Hello "
std::boolalpha 布尔值文字显示 true → "true"
std::showpos 显示正数符号 42 → +42
std::uppercase 大写格式(与hex/scientific配合) 0xff → 0XFF

重要特性

  1. 持久性设置:多数格式设置会保持生效,直到被显式修改
  2. 作用域控制:可通过{}限定格式作用范围
    {std::ios_base::fmtflags f = std::cout.flags();  // 保存状态std::cout << std::hex << 255;                   // 临时使用十六进制std::cout.flags(f);                             // 恢复状态
    }
    
  3. 性能影响:频繁切换格式设置可能影响I/O性能(建议批量处理)

对结构体添加输入输出支持

这部分相当简单,请看示例代码:

struct person {std::string name;int age;friend std::istream &operator>>(std::istream &is, const person &p) {is >> p.name >> p.age;return is;}friend std::ostream &operator<<(std::ostream &os, const person &p) {os << p.name << ": " << p.age;return os;}
};person p;
std::cin >> p;
std::cout << p << '\n';

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/886665.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电商与ChatGPT结合:如何利用AI提升销售额,案例分析及应用策略

在当今数字化浪潮中,AI技术正以前所未有的速度渗透到各个行业,电商直播带货领域也不例外。 曾经一个5人团队,在团队规模恒定的情况下,巧妙借助ChatGPT与各类软件的融合之力,成功实现了年销售额从2000万跃升至2500万甚至3000万的飞跃,这无疑彰显了AI在电商领域的巨大潜力。…

逻辑推理

肯前比肯后 否后比否前 肯后否前无必然联系 前推后 如果 就 都 一定 后推前 只有 ...才 ... 除非。。。否则不 。。。 B -> A 除非。。。否则 。。。 -B -> A 谁必不可少 谁就在箭头后面 或关系 否一推一 如 A或B为真 -A->B/ -B-> A 快速做题 - 排除出现…

BTB04-ASEMI电动工具专用BTB04

BTB04-ASEMI电动工具专用BTB04编辑:ll BTB04-ASEMI电动工具专用BTB04 型号:BTB04 品牌:ASEMI 封装:TO-220F 正向电流:8A 反向电压:600V~800V 引脚数量:3 芯片个数:2 芯片尺寸: 漏电流:>10ua 恢复时间: 包装方式:管装 封装尺寸:如图 特性:双向可控硅 工作结温:…

10款最适合大数据项目管理工具(2025年)

在当今数据驱动的时代,大数据项目管理已成为企业成功的关键因素之一。随着数据量的爆炸式增长,传统的项目管理方法已无法满足需求,企业需要借助专业的软件工具来高效管理复杂的大数据项目。本文将为您介绍10款最适合大数据项目管理的软件工具,帮助您在2025年及未来更好地应…

第十六章 采购管理(2025年详细解析版)

目录导学什么是采购管理?定义内容16.1 管理基础什么是协议定义协议的形式什么是合同定义内容合同注意事项项目采购与项目管理项目买卖方内部卖方招投标的流程发展趋势和新兴实践(了解)采购新趋势16.2 项目采购管理过程项目采购管理过程ITTO裁剪时需要考虑的因素在敏捷或适应…

面试官:说说你项目中JWT的执行流程?

JWT 在目前的项目开发中使用到的频率是非常高的,因此它也是面试常问的一类问题,所以今天我们就来看看“项目中 JWT 的执行流程?”这个问题。 1.什么是 JWT? JWT(JSON Web Token) 是一种开放标准(RFC 7519),用于在网络应用间安全传输信息,通常用于身份验证和信息交换。…

【日记】文竹已经长得比路灯还要高了(1069 字)

正文最近陷入了一个深刻的情感漩涡。一边有些嫌恶爱情,一边又为它焦虑。一边觉得自己只有友谊已经足够了,一边又看见大多数友情并不能如爱情一般陪伴那样长的时间,不说二三十年,甚至不到十年可能便会消亡。觉得其实自己仍然需要它。然而目前这个不太喜欢、又需要一个东西的…

苹果使用AI让皮克斯的灯具复活了。

苹果让皮克斯著名的开场灯具复活,发布了一项新的研究,其中描述它的形容词并不是你通常会在AI研究中使用的那些。 这与我们习惯的一切都不同。它在技术上并不更聪明、更强大,也不是那些害怕AI的人噩梦般的存在。 相反,它似乎是科技巨头首次尝试以不同的方向提升AI和机器人智…

react-native-snap-carousel 轮播图卡在中间的问题

今天在使用react-native-snap-carousel组件的时候,发现一个问题,就是轮播有时候会卡在两个轮播图之间,不左不右的。研究了半天,才发现,开启动量滚动即可 关于enableMomentum的解释 enableMomentum 是 React Native 中 ScrollView 和 FlatList 组件的一个属性,用于控制滚动…

安川机器人维修JZRCR - YPP01 - 1示教器按键故障

在工业生产领域,安川机器人发挥着极为重要的作用。然而,像JZRCR - YPP01 - 1示教器按键出现故障这样的问题会影响机器人的正常运行。一、安川机器人JZRCR - YPP01 - 1示教器按键故障的初步检查外观检查首先,在进行任何深入维修之前,对示教器进行外观检查是必要的。检查按键…

Svelte 最新中文文档教程(13)—— 样式

前言 Svelte,一个非常“有趣”、用起来“很爽”的前端框架。从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1:Svelte 以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构…