CC19.【C++ Cont】scanf/printf 和 cin/cout的对比

目录

1.格式上

1.scanf/printf

2.cin/cout

★2.性能上

先说结论

演示

 1.用scanf读取data.txt的全部数字,计算所需时间

运行结果

 2.用cin读取data.txt的全部数字,计算所需时间

运行结果

简单解释

举例

详细解释性能上的差异

背景知识

重点强调影响性能的两句话

3.提高cin/cout的性能的两个方法

1.解除同步

2.取消绑定

3.模版

4.测试加上后再读取1~10000000个数字所需要的时间

运行结果

4.总结


1.格式上

1.scanf/printf

1.不能自动识别输入数据的类型,需要手动指定格式(%d,%s,...)字符串,容易出现格式错误.需要确保格式字符串与变量类型匹配,否则会导致未定义行为

2.格式化输出更精确直观,特别适合复杂格式的输入输出

复习

32.【C语言】详解scanf

31.【C语言】详解printf

7.5【C语言】补充printf细节

2.cin/cout

cin和cout会根据变量类型自动处理输入输出,避免格式化错误,使用简单

例如:cout默认不会输出六位小数,自动忽略小数点后多余的0,而printf函数打印浮点数的时候,小数点默认打印6位.

★2.性能上

先说结论

***scanf/printf通常比cin/cout快***

演示

先生成存储1~10000000的数字(数据量越大差异越明显)的data.txt,以便于scanf和cin读取

#include <stdio.h>
#include <time.h>
int main()
{
	int a = 0;
	FILE* pf = fopen("data.txt", "w+");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	printf("正在写入...\n");
	for (int i = 1; i <= 10000000; i++)
	{
		fprintf(pf, "%d ", i);
	}
	fclose(pf);
	printf("写入成功!");
}

附data.txt的下载链接: https://pan.baidu.com/s/1amRp8C7q7XD0yIv9F8KfBg?pwd=z8dy 提取码: z8dy

 1.用scanf读取data.txt的全部数字,计算所需时间

#include <iostream>
#include <ctime>
using namespace std;
int main()
{
	int a = 0;
    //freopen将stdin重定向到文件,即scanf可以文件中读取数据
	FILE* pf = freopen("data.txt", "r",stdin);
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	clock_t begin = clock();
	for (int i = 1; i <= 10000000; i++)
	{
		scanf("%d", &a);
	}
	clock_t end = clock();
	printf("time=%dms", end - begin);
	return 0;
}

运行结果

 2.用cin读取data.txt的全部数字,计算所需时间

#include <iostream>
#include <ctime>
using namespace std;
int main()
{
	int a = 0;
    //freopen将stdin重定向到文件,即scanf可以文件中读取数据
	FILE* pf = freopen("data.txt", "r",stdin);
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	clock_t begin = clock();
	for (int i = 1; i <= 10000000; i++)
	{
		cin >> a;
	}
	clock_t end = clock();
	cout<<"time="<< end - begin<<"ms";
	return 0;
}

运行结果

简单解释

cin和cout由于要兼容C语言的输入和输出,封装实现较复杂,通常比scanf/printf慢

举例

https://ac.nowcoder.com/acm/problem/227585

本题的输入描述中有这样两个需要重点关注的地方:

1.1≤T≤1000000 T最大可以到100万,数据量很大!!!

2.请选择较快的读入方式

显然需要用scanf/printf来输入和输出数据

详细解释性能上的差异

要想深刻了解cin需要看官方网站对此的解释:https://legacy.cplusplus.com/reference/iostream/cin/

背景知识

1.在 C++ 中,标准输入输出流(如cin和cout)由C++ 标准库提供,而在 C 语言中,标准输入输出函数(如scanf和printf)由C标准库提供. C++ 从C发展而来,因此C++ 标准库的输入输出流系统需要与 C 标准库的输入输出系统兼容来确保在同一程序中能够混合使用C和C++的输入输出函数

为了兼容,C++标准库默认会将cin 、cou等C++ 流对象与stdin、stdout等C标准库的流对
同步在一起.这种同步操作意味着每次使用 cin 或 cout 时,都会自动刷新 C 标准
库的缓冲区
,确保C++和C的I/O一致


2. 默认情况,cin 和 cout 之间存在一种绑定关系,即每当从cin 读取数据时,任何之前通过cout输出的内容都会被强制刷新到屏幕上(这个影响性能,后面会解释).这个机制保证了输出内容能够立即显示给用户,这对于交互式程序非常有用.但这种绑定也可能导致性能问题,特别是在需要频繁读取大量数据的情况下.这是因为每次从cin读取数据都会触发一次输出缓冲区的刷新,即使实际上没有进行输出操作,也会浪费时间

重点强调影响性能的两句话

cin is tied to the standard output stream cout (see ios::tie)

By default, cin is synchronized with stdin (see ios_base::sync_with_stdio).

1.cin与标准输出流cout绑定(be tied to) 2.默认情况,cin与stdin同步(synchronized v.同步)

显然可以得出:如果想优化cin/cout的性能,有两个解决方法:1.解除同步 2.取消绑定

3.提高cin/cout的性能的两个方法

1.解除同步

使用以下代码可以关闭C++标准库与C标准库之间的I/O同步,不再自动刷新C标准库的缓冲区,cin和cout独立进行,提高性能

//为false即关闭同步,前面为ios_base为取消与C风格的I/O的同步`
ios::sync_with_stdio(false);//在ios作用域内使用sync_with_stdio函数

(这里的sync_with_stdio全称: synchronized_with_standard_input_output)

注意:只有在只使用cin/cout进行 I/O,而不涉及C的I/O函数的情况下才是安全的!!! 1.如果与C的I/O函数混合使用可能导致不可预期的行为,如输出顺序错乱.2.I/O 操作可能不再是线程安全的,特别是在多线程环境中需要谨慎使用

2.取消绑定

使用以下代码可以解除标准输入流cin与标准输出流cout之间的默认绑定,当从 cin 读取数据时,cout 的缓冲区就不会被刷新(竞赛题要的只是最终结果,输出不需要实时显示给用户),当程序需要同时处理多个输入输出流时,解除绑定有助于减少同步带来的延迟,提高性能

cin.tie(0);
cout.tie(0);

或者写成

cin.tie(nullptr);
cout.tie(nullptr);

3.模版

ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//do_something

★特别提醒:解除同步和取消绑定后不能与C的I/O函数(如scanf和printf)混合使用,会不安全!

4.测试加上后再读取1~10000000个数字所需要的时间

#include <iostream>
#include <ctime>
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int a = 0;
	FILE* pf = freopen("data.txt", "r",stdin);
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	clock_t begin = clock();
	for (int i = 1; i <= 10000000; i++)
	{
		cin >> a;
	}
	clock_t end = clock();
	cout<<"time="<< end - begin<<"ms";
	return 0;
}

运行结果

性能显著提升!甚至比scasnf的性能要好!

4.总结

如果输入的数据量比较小(10^6 以内),使用cin和coutscanf和printf
但是如果输入的数据量比较大(10^9 左右),推荐使用scanf和printf优化后的cin和cout

注:一些极端情况下,当输入输出的规模非常大的时候,scanf和printf也不能满足,会使用快速读写的方式,之后会讲

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值