适用对象: A 班同学。默认你已完成第 1 课,会用 cin / cout 独立写 GESP 四级题 使用方式: 自学讲义。所有示例必须在 Dev-C++ 里亲手跑一遍,不许只看 学完本教程,你应该能:
使用说明:
| 符号 | 含义 |
|---|---|
| ⭐ | 基础题,热身 |
| ⭐⭐ | 实战题,对应复赛 T1 难度 |
| ⭐⭐⭐ | 冲刺题,考场排错实战 |
| ⚠️ | 考场易错点 |
| 📝 | 规则/结论速记 |
平时刷题:键盘输入 → 屏幕输出。 CSP-J 复赛:程序自己打开文件读数据,把答案写进另一个文件,全程没有键盘和屏幕什么事。
题目名叫 apple,你的程序就必须:
apple.in 读入数据apple.out评测机拿你的 apple.out
和标准答案比对(忽略行末空格和文末空行)。文件名错一个字母,评测机连你的输出都找不到——0
分,代码写对也是 0 分。
把"键盘/屏幕"切换到"文件",C++
里最省事的办法就是一个函数:freopen。
📝 freopen = 重新打开标准输入/输出,让 cin 从文件读、cout 往文件写。
#include <cstdio> // bits/stdc++.h 里已包含
FILE* freopen(const char* filename, // 文件名
const char* mode, // 打开方式
FILE* stream); // 要重定向的流三个参数,一个一个看:
| 参数 | 考场上写什么 | 含义 |
|---|---|---|
filename |
"apple.in" / "apple.out" |
文件名字符串,必须带双引号,拼写和题目要求一字不差 |
mode |
"r" / "w" |
"r" = read 读入(给 .in
用);"w" = write 写出(给 .out 用) |
stream |
stdin / stdout |
stdin = 标准输入(cin 的来源);stdout =
标准输出(cout 的去向) |
排列组合一下,考场只有两种搭配:
freopen("apple.in", "r", stdin); // 让 cin 改从 apple.in 读
freopen("apple.out", "w", stdout); // 让 cout 改写进 apple.out📝 记忆口诀:in 配 r 配 stdin,out 配 w 配 stdout——输入对输入,输出对输出。
📝 模式其实还有
"a"(追加,不清空原文件),但考场用不到,知道有这回事就行。
#include <bits/stdc++.h>
using namespace std;
int main() {
freopen("apple.in", "r", stdin);
freopen("apple.out", "w", stdout);
int a, b;
cin >> a >> b; // 从 apple.in 读,不从键盘读
cout << a + b << endl; // 写进 apple.out,屏幕上什么都看不到
return 0;
}关键点:freopen 只改"源头"和"去向",后面的代码一行不用动。cin、cout、scanf、printf 全部自动跟着走。
⚠️
运行这样的程序,黑窗口(控制台)一片空白或一闪而过是正常的——输出进了文件,不在屏幕上。去
.cpp 所在的文件夹找 apple.out 看结果。
"w" 每次运行都会先把 apple.out
清空再写。所以:
.out.in 文件用 "w"
打开了,输入文件会被瞬间清空——数据全没了⚠️ 模式写反是最惨的事故之一:
freopen("apple.in", "w", stdin); // 灾难:apple.in 被清空,还读不到东西freopen 成功时返回那个流,失败时返回
NULL(最常见的原因:apple.in
根本不存在)。调试期可以这样写:
if (freopen("apple.in", "r", stdin) == NULL) {
// 走到这里说明文件没找到:查文件名、查扩展名、查文件位置
return 1;
}⚠️ 这段检查是调试期帮你定位问题的,正式提交写普通两行模板即可。
⚠️ freopen 失败的典型症状:黑窗口一闪而过,.out
是空的或内容乱七八糟。看到这个症状,第一反应就是去查 .in
文件名。
以题目 apple 为例,从拿到题到交卷:
apple,代码保存为
apple/apple.cpp#include <bits/stdc++.h>
using namespace std;
int main() {
freopen("apple.in", "r", stdin);
freopen("apple.out", "w", stdout);
// ===== 下面就是你的正常代码 =====
return 0;
}apple.cpp 旁边新建
apple.in,把样例输入粘进去保存,按 F11 运行(Dev-C++
运行时就在 .cpp 所在文件夹里找 apple.in),打开生成的
apple.out 对答案⚠️ apple.in 特别容易建成
apple.in.txt:Windows 默认隐藏扩展名。在资源管理器里勾选
查看 → 文件扩展名,确认文件名真的是
apple.in。
📝 题目要求什么文件名就写什么文件名,一字不差。CSP-J 复赛惯例是全小写,但以题目 PDF 为准。
//freopen("apple.in", "r", stdin);
//freopen("apple.out", "w", stdout);调试时注释掉,用键盘屏幕;交卷前取消注释。
⚠️ 每年都有人忘了取消注释就交卷——0 分。用这个方法,就在草稿纸上写一行大字:"交卷前恢复 freopen!"
freopen 从头到尾不注释。想换测试数据就改 apple.in
的内容,运行后看 apple.out。
和考场环境一模一样,不存在"忘了恢复"的问题。代价是没有交互输入,调试信息只能往
apple.out 里打(交卷前记得删)。
#ifndef ONLINE_JUDGE
freopen("apple.in", "r", stdin);
freopen("apple.out", "w", stdout);
#endif很多评测网站(如洛谷)编译时会定义 ONLINE_JUDGE
这个宏:在网站评测时 freopen 自动消失,在你自己电脑上测试时 freopen
生效。一份代码两头用,不用来回注释。
⚠️ CSP-J 考场不这么写。考场要求文件输入输出,直接写死两行模板,别玩花样。
考前把这张表过一遍,每条都值 100 分:
| # | 事故 | 后果 | 自查动作 |
|---|---|---|---|
| 1 | 文件名拼错/大小写错:Apple.in、aple.in |
0 分 | 对照题目 PDF 逐字母核对 |
| 2 | 建成了 apple.in.txt |
本地测试读不到数据 | 资源管理器打开扩展名显示 |
| 3 | 调试时注释了 freopen,交卷忘恢复 | 0 分 | 全文搜索 //freopen |
| 4 | "r" 和 "w" 写反 |
.in 被清空 |
口诀:in-r-stdin,out-w-stdout |
| 5 | 往 stdout 打了调试信息("debug"、中间结果) | 答案错误 | 全文搜索 cout,逐个确认 |
| 6 | 结尾写 system("pause")、getchar()
等输入 |
超时 | 直接 return 0 结束 |
| 7 | 代码没放进题目要求的文件夹,或文件夹名错 | 0 分 | 对照考场要求检查路径 |
| 8 | 在网站提交时带着 freopen | 0 分或 WA | 网站提交前注释掉(或用姿势三) |
不看讲义,默写 freopen 考场两行模板。然后指出下面每一行错在哪:
freopen(apple.in, "r", stdin); // (a)
freopen("apple.out", "r", stdout); // (b)
freopen("apple.in", "w", stdin); // (c)
freopen("apple.in", "r", stdout); // (d)题目名 plus:从 plus.in
读入两个整数(一行,空格隔开),把它们的和写进
plus.out。
样例输入(plus.in):
3 5
样例输出(plus.out):
8
要求:建 plus 文件夹、写 plus.cpp、建
plus.in
测样例,全程不许看屏幕输出。再自己编两组数据测一遍(比如
100 200、-7 7)。
下面是小明为题目 apple 写的代码,共有 5
处会导致爆零或挂分的问题,全部找出来:
#include <bits/stdc++.h>
using namespace std;
int main() {
freopen("Apple.in", "r", stdin);
freopen("apple.out", "r", stdout);
int n, s = 0, x;
cin >> n;
cout << "n = " << n << endl; // 调试看看读对没有
for (int i = 1; i <= n; i++) {
cin >> x;
s += x;
}
cout << s << endl;
system("pause");
return 0;
}(补充线索:小明的代码保存为 apple.cpp,但他的输入文件叫
apple.in.txt。)
模板:
freopen("apple.in", "r", stdin);
freopen("apple.out", "w", stdout);.out 应该用 "w" 写模式;用
"r" 打开一个不存在的 .out
会直接失败,答案写不进去.in 用 "w"
会把输入文件瞬间清空,灾难stdin,不是
stdout#include <bits/stdc++.h>
using namespace std;
int main() {
freopen("plus.in", "r", stdin);
freopen("plus.out", "w", stdout);
int a, b;
cin >> a >> b;
cout << a + b << endl;
return 0;
}plus.in 里写 3 5,运行后
plus.out 里应该是 8。换成 100 200
应得 300,-7 7 应得
0。全程屏幕空白是正常的,答案在文件里。
"Apple.in" 大写 A:题目要求
apple.in,文件名必须一字不差"r" 模式:应为
freopen("apple.out", "w", stdout),否则答案写不进去cout << "n = " << n << endl;
没删:这行会写进 apple.out,答案直接判错system("pause"):程序卡在等按键,评测超时apple.in.txt:freopen 找不到
apple.in,读入失败——资源管理器打开"显示文件扩展名"就能发现📝
函数原型:freopen("文件名", "模式", 流);
📝 考场两行:
freopen("题目名.in", "r", stdin);
freopen("题目名.out", "w", stdout);📝 口诀:in 配 r 配 stdin,out 配 w 配 stdout。
📝 三个铁律:
system("pause")