文件读入输出、数据生成、对拍
文件读入输出
知识介绍
顾名思义,程序将会从文件中读入数据,也会将数据输出到文件中(两文件可不同)
在有时,如果程序想要测试数据较大的样例
可能会因为要输入的东西过多而无法完成
这时,如果我们已经有了输入数据的文件
便可以通过文件读入输出来使程序自动完成数据的输入与输出
使用方法
freopen("a.in", "r", stdin)
头文件 \(cstdio(stdio.h)\) 中包含函数 \(freopen\),用于重定向输入输出流
freopen("a.in", "r", stdin);//使程序从文件 a.in 中读入
fclose(stdin);//恢复 输入流 的重定向
\(r\) 为 \(read\) 的简写,表示“只读访问”
\(stdin\) 表示被重定向的文件流为 输入流
freopen("a.out", "w", stdout)
freopen("a.out", "w", stdout);//使程序输出到文件 a.out
fclose(stdout);//恢复 输出流 的重定向
\(w\) 为 \(write\) 的简写,表示“只写访问”
\(stdout\) 表示被重定向的文件流为 输出流
代码示例
在一般情况下,将 \(freopen\) 两个语句放到主函数开头
将 \(fclose\) 两个语句放到主函数末尾(\(return\ 0;\)之前)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
typedef long long LL;
int read() {
int x = 0, f = 1; char ch;
while(! isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 3) + (x << 1) + (ch ^ 48));
return x * f;
}
template <class T> T Max(T a, T b) { return a > b ? a : b; }
template <class T> T Min(T a, T b) { return a < b ? a : b; }
int main() {
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
fclose(stdin);
fclose(stdout);
return 0;
}
注:
-
文件 \(a.in\) 和 \(a.out\) 应和程序在同一目录下
当不存在文件 \(a.out\) 时,会由程序自动建立
-
当由本地评测机对程序进行数据测试时
一般也是采用文件读入输出+文件文本对比的方式判断程序运行情况
-
文件读入输出适用于数据较大的情况
-
输入输出文件名可以自定义,不一定以 \(.in\) 和 \(.out\) 为后缀名
数据生成
知识介绍
我们在本地进行编译测试程序时,一般使用的都是小数据
但在某些情况下,我们需要用大数据来对程序进行测试
显然,有时大数据会因为数据量过大而无法手动生成
此时,便需要我们利用程序编写数据生成的代码
来辅助我们对于代码的调试
使用方法
在头文件 \(cstdlib(stdlib.h)\) 中
包含两个函数 \(rand()\) 和 \(srand()\) 及一个整数常量 \(RAND\_MAX\)
RAND_MAX
一般情况下,\(RAND\_MAX\) 在 \(Windwos\) 系统中为 \(32767\)
而在类 \(Unix\) 系统中为 \(2147483647\)
rand()
\(rand()\) 函数返回区间 \([0,RAND\_MAX]\) 内的随机整数 \(int\)
srand()
\(srand()\) 函数接受一个无符号 \(32\) 位整数的参数作为 \(seed\) (随机种子)
此后,\(rand()\) 函数按一定规则生成随机数
种子确定后,每次 \(rand()\) 得出的值便被固定(实际上,这种随机叫做伪随机)
注:默认情况下,\(seed\) 为 \(1\)
time(0)
那么此时出现了问题,如果想生成随机数
需要事先将一个随机数当作种子,那么这个随机数从哪里来呢?
对于该问题,一个简单的解决方法是
使用头文件 \(ctime(time.h)\) 中的 \(time()\) 函数
\(time(0)\) 返回从 \(1970\) 年 \(1\) 月 \(1\) 日 \(0\) 时 \(0\) 分 \(0\) 秒 (\(Unix\) 纪元 )到现在的秒数
代码示例
以下程序 \(random(x)\) 函数生成 \([0,n-1]\) 的整数
#include <cstdlib>
#include <ctime>
int random(int n) {
return (long long)rand() * rand() % n;
}
int main() {
srand((unsigned)time(0));//(unsigned)可以省略,强制类型转换
return 0;
}
对拍
知识介绍
对拍是一种用于调试程序的方法
当我们写出一个程序,但不知道所用的方法是否正确时
如果我们已经拥有一份运行正确的代码
那么我们可以通过对拍的方法来找到使得我们程序错误的样例
\(Windows\) 系统下有 \(bat\) 批处理脚本
类 \(Unix\) 系统下有 \(bash\) 脚本
都可以用来编写对拍程序
此处介绍使用 \(C/C++\) 语言编写对拍程序的方法
使用方法
system()
头文件 \(cstdlib(stdlib.h)\) 中函数 \(system\) 接受字符串参数
并将该字符串作为系统命令执行
例如:system("C:\\random.exe") 执行 \(C\) 盘根目录下的 \(random.exe\) 文件
fc/diff
\(Windows\) 系统命令 \(fc\) 和 类\(Unix\) 系统命令 \(diff\) 可以进行文件比对
后接两个文件路径,比较两文件是否一致,并返回 \(0\)(一致)或 非零值(不一致)
注:该命令在文本比对时默认忽略行末空格和行尾回车
与一般评测网站和评测机所使用的文本对比方式相同
若需要特别的文本比对方式,需要另加参数
注意事项
-
当命令行中所所传入的文件路径与当前命令行所处路径相同时,可省略文件路径

-
文件路径查看方式
右键单击文件 --> 属性 --> 位置
-
显示文件扩展名(后缀名)
我的电脑 --> 查看 --> 文件扩展名

-
打开命令行
①\(Win+r\) --> 输入 "cmd" --> 回车
②按如图方式输入 “cmd” 并回车
注:方法②打开的命令行会自动跳转至输入“cmd”的界面所在目录

对拍演示
四个程序:
\(a.cpp:\) 未知对错程序
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
int a, b;
cin >> a >> b;
cout << (a + b) << endl;
fclose(stdin);
fclose(stdout);
return 0;
}
\(b.cpp:\) 正确程序
#include <stdio.h>
int main() {
freopen("a.in", "r", stdin);
freopen("b.out", "w", stdout);
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", a + b);
fclose(stdin);
fclose(stdout);
return 0;
}
\(rand.cpp:\) 数据生成器
#include <cstdio>
#include <ctime>
#include <cstdlib>
using namespace std;
int main() {
freopen("a.in", "w", stdout);
srand(time(0));
printf("%d %d\n", rand(), rand());
return 0;
}
\(dp.cpp:\) 对拍程序
#include <cstdio>
#include <ctime>
#include <cstdlib>
using namespace std;
int main() {
int cnt = 0;
while(1) {
system("rand.exe");
double t1 = clock();
system("a.exe");
double t2 = clock();
system("b.exe");
if(system("fc a.out b.out")) { printf("WA\n");return 0; }
else printf("AC: %d T: %.2f\n", ++ cnt, (t2 - t1) / 1000.0);
}
return 0;
}
注:\(clock()\) 函数在头文件 \(ctime(time.h)\) 中
返回程序从运行到现在的时间(单位:\(ms\)(\(Windows\)系统)、\(s\)(类\(Unix\)系统))
将这四个程序都放在桌面
编译运行前三个程序,生成对应的可执行文件(\(.exe\) 文件)后
编译运行对拍程序即可进行对拍

当两程序输出结果不同时,会在屏幕上输出 "WA" 并结束程序

浙公网安备 33010602011771号