蒟蒻博主昨天做了一道题, 重载了高精度结构体的 > > 、 < < >>、<< >>、<<运算符, 以便用 c i n 、 c o u t cin、cout cin、cout直接读入。
因为有点卡常, 只好打开了ios_base::sync_with_stdio(false)
然而在一组数据上死活 W A WA WA:
这个点输出 0 0 0说明是一个特判的点, 根本不应该 W A WA WA。
然后蒟蒻博主把std代码贴下来对拍了所有合法情况, 发现非零的情况根本没锅…
那么这是什么操作呢? 蒟蒻博主又在每组数据处理之前加了 f f l u s h ( s t d o u t ) fflush(stdout) fflush(stdout), 然后发现可以 A A A。
博主又把
ios_base::sync_with_stdio(false);
删掉, 发现不加 f f l u s h fflush fflush也可以 A A A…
仔细看才发现啊中间的特判是这么写的:
int T, n, k;
ios_base::sync_with_stdio(false);
cin >> T;
W (T--)
{
cin >> n >> k;
if (n > k || k == 0 || n == 0) {puts("0 1"); continue;}
......
原来是把我 p u t s ( ) puts() puts()的东西吃掉了…
那么ios_base::sync_with_stdio(false)
到底搞了什么操作?
看了网上大神们的博客蒟蒻才明白一点。
在普通状况下, 我们的 s t d o u t stdout stdout并不是直接输出的, 而是暂时存在一个叫缓冲区的地方。
缓冲区也分为三种:
- 全缓冲: 直到系统缓冲区满了再一次全部输出, 例如对磁盘文件的读写。
- 行缓冲:读取到换行符或行缓冲满了之后再输出, 例如 s t d i n / s t d o u t stdin/stdout stdin/stdout。
- 不带缓冲:直接输出 ,不放在缓冲区里面。
如何验证 s t d i n / s t d o u t stdin/stdout stdin/stdout是行缓冲? 实际上很简单:
#include <bits/stdc++.h>
using namespace std;
int main(){
printf("hello world!");
_Exit(0);
}
当然这玩意应该放到linux下运行, windows系统会自动帮你刷新缓冲区。(windows下面是_exit(0))
然后我们发现似乎并没有任何输出, 因为_exit(0)
直接并没有刷新缓冲区就直接强制退出了。
如果加上’\n’:
那么我们再来看下读写磁盘文件的缓冲:
#include <bits/stdc++.h>
using namespace std;
string a;
int main(void)
{
freopen("233.out", "w", stdout);
for (int i = 1; i <= 1022; ++i) a += '2';
for (int i = 1; i <= 10; ++i)
cout << a << '\n'; //输出长度为1023
/*使用
printf("%s\n", a.c_str());
会得到同样效果*/
}
在调试模式下运行, 输出第 5 5 5个 a a a的时候会是这样的:
注意到下面只有4个 2 2 2, 这说明全缓冲的缓冲区大小是 4096 b y t e s 4096\ bytes 4096 bytes(windows下)。
但如果换成
#include <bits/stdc++.h>
using namespace std;
string a;
int main(void)
{
freopen("233.out", "w", stdout);
for (int i = 1; i <= 1022; ++i) a += '2';
for (int i = 1; i <= 10; ++i)
cout << a << endl;
}
就会发现每次输出的时候都直接写在了文件里面。
这是因为
e
n
d
l
、
f
l
u
s
h
endl、flush
endl、flush都会强制刷新缓冲区, 也就是为什么有人说cout <<'\n'
比cout<<endl
快的原因。
然后我们加上ios_base::sync_with_stdio(false)
, 发现无论cout<<'\n'
还是cout<<endl
都会直接输出在文件里面, 等于强制转换到了不带缓冲模式, 自然比输出到缓冲区再
f
l
u
s
h
flush
flush出来更快。
那么这个时候的 p u t s ( " " ) / p r i n t f ( " " ) puts("")/printf("") puts("")/printf("")输出到了哪里?我们再做一个测试:
#include <bits/stdc++.h>
using namespace std;
string a;
int main(void)
{
freopen("233.out", "w", stdout);
ios_base::sync_with_stdio(false);
for (int i = 1; i <= 10; ++i) a += '2';
for (int i = 1; i <= 10000; ++i)
cout << a << endl, puts("000");
}
每次我们 p u t s ( " " ) puts("") puts("")出去的输出为 4 b y t e s 4\ bytes 4 bytes, 仍然被放在全缓冲区里, 当操作到1025次时缓冲区满, 自动输出。
所以这道题因为输出 1 0 1\ 0 1 0的大小远远小于 4096 b y t e s 4096\ bytes 4096 bytes,等于是 1 0 1\ 0 1 0的情况全部被放到后面, 程序退出时清空缓存区的时候输出了…
这也说明了 O J OJ OJ评测的时候是把输出定向到了文件中, 否则 p u t s ( " " ) puts("") puts("")会直接输出。