C++入门:输入输出(下)——scanf/printf和cin/cout对比

scanfprintf 是C语言中的标砖输入输出函数,而cincout 是C++语言中的必遭护照那输入输出流对象。它们各自有优缺点,整体上来说cincout 会更方便,但有时候我们也不得不使用scanfprintf

1. 格式控制差异

  • sacnf he1printf 不能自动识别输入数据的类型,选哟手动指定格式字符串,容易出现格式错误。我们需要确保格式字符串与变量类型匹配,否则会导致未定义行为。
  • cincout 会根据变量类型自动处理输入输出,避免格式错误。相对scanfpintf 来说,C++的cincout 更加易用。
  • scanfprintf :格式化输出更精确直观,特别适合复杂格式的输入输出,比如:在要求指定格式输出的时候,printf 函数就比cout 更加方便和灵活。
#include <iostream>
#include <string>

using namespace std;

int main()
{
	float a = 3.50;
	double d = 16.50;
	
	cout << "cout" << a << " " << d << endl;
	printf("printf: %f %lf\n", a, d);
	return 0;
}

输入结果如下:

0

区别:

  1. cout 默认不会输出六位小数,自动忽略小数点后多余的0printf 函数打印浮点数的时候,小数点默认打印6位。
  2. cout 在输出的时候不与要指定格式,printf 则需要明确的格式。

2. 性能差异

2.1 案例演示

结论:scanfprintf 通常比cincout 快。

**原因:**cin和cout由于要考虑兼容C语言的输入和输出,封装实现更加复杂,通常比scanf和printf稍慢,这种差异在大多数应用场景中可以忽略不计。

但是在竞赛题目中,尤其是当输入、输出数据量较大时,使用cin和cout完成输入输出,经常会出现超时。而scanfprintf 就不存在类似的问题。

请看下面案例,我们来对比一下:

案例:数字游戏

使用cincout

#include <iostream>
using namespace std;

int t, x;

int main()
{
	cin >> t;
	while (t--)
	{
		cin >> x;
		int ret = 0;
		while (x)
		{
			int count = 0, high = 0;
			int tmp = x;
			while (tmp)
			{
				//计算最右边的1代表的值
				int low = tmp & -tmp;
				//如果low中剩余的1就是最后一个1
				
				//就是最左边的1
				if (tmp == low)
				{
					high = low;
				 } 
				 //去掉最右边的1
				 tmp -= low;
				 count++; 
			}
			
			if (count % 2 == 0)
			{
				x -= high;
				
			}
			else
			{
				x ^= 1;
			}
			ret++;
		}
		cout << ret <<endl;
	}
	
	return 0;
}

使用scanfprintf

#include <iostream>
using namespace std;

int t, x;

int main()
{
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d", &x);
		int ret = 0;
		while (x)
		{
			int count = 0, high = 0;
			int tmp = x;
			while (tmp)
			{
				//计算最右边的代表的值
				int low = tmp & - tmp;
				//如果low中剩余的1就是最后一个1
				
				//就是最左边的1
				if (tmp == low)
				{
					high = low;
				 } 
				 //去掉最右边的1
				 tmp -= low;
				 count++;
				  
			}
			
			if (count % 2 == 0)
			{
				x -= high;
			}
			else
			{
				x ^= 1;
			}
			ret++;
		}
		printf("%d\n", ret);
		
	}
	
	return 0;
 } 

可以看出,在这个案例中输入的数据量是比较大的。在输入数据的时候如果使用cin ,会出现超时的问题,但是换成scanf 的方式就能正确的通过。这就是因为两者性能上的差异导致的。

为什么cin/cout 的性能要低于scanf/printf 呢?

有什么办法能优化吗?

参考这篇:

【提高】std::ios::sync_with_stdio(false)的作用和原理

总结:

  1. C++中为了支持混合使用cin/coutscanf/printf ,C++标准库默认会将cincout 等C++流对象与stdinstdout 等C标准库的流对象同步在一起。这种同步操作意味着每次使用cincout 时,都会自动刷新C便准库的缓冲区,。以确保C++和C的I/O是一致的。这就导致了性能的下降。
  2. 在默认情况下,cincout 之间存在一种绑定关系。这种绑定意味着,每当从cin 读取数据时,任何之前通过cout 输出的内容都hi被强制刷新到屏幕上。这种绑定也看了能导致性能问题,特别是在需要频繁读取大量数据的情况下。

2.2 优化方案

下面我们看一下scanfcin 的差异,然后看看如何进行优化。

代码:

#include <iostream>
#include <ctime>
#include <cstdio>

using namespace std;
const int num = 10000000;

int main()
{
	int i, x;
	//freopen是将stdin重定向到文件
	//意思是scanf可以文件中读取数据
	freopen("data.txt", "r", stdin);
	clock_t t1, t2;
	t1 = clock();
	for (i = 0; i < num; i++)
	{
		scanf("%d", &x);
	 } 
	 t2 = clock();
	 cout << "Runtime of scanf: " << t2 - t1 << " ms" << endl;
	 return 0;
}
#include <iostream>
#include <ctime>
#include <cstdio>

using namespace std;
const int num = 10000000;

int main()
{
	//freopen是将stdin重定向到文件
	//意思是scanf可以文件中读取数据
	freopen("data.txt", "r", stdin);
	int i, x;
	clock_t t1, t2;
	t1 = clock();
	for (i = 0; i < num; i++)
	{
		cin >> x;
	 } 
	 t2 = clock();
	 cout << "Runtime of cin: " << t2 - t1 << " ms" << endl;
	 return 0;
}

1

2

用一个测试数据文件举例。

cin 进行优化,代码如下:

#include <iostream>
#include <ctime>
#include <cstdio>

using namespace std;
const int num = 10000000;

int main()
{
	ios::sync_with_stdio(false); //取消C语言输入输出区的同步 
	cin.tie(0); //取消cin和cout的绑定 
	freopen("data.txt", "r", stdin);

	int i, x;
	clock_t t1, t2;
	t1 = clock();
	for (i = 0; i < num; i++)
	{
		cin >> x;
	 } 
	 t2 = clock();
	 cout << "Runtime of cin: " << t2 - t1 << " ms" << endl;
	 return 0;
}

运行结果:

3

所以我们在使用sanf /printfcin /cout 抉择的时候,如果要追求性能,那就用scanf /printf ,或者优化后的cin /cout ,如果不追求性能,直接用cin /cout 就行。

Tips:

  • 如果输入的数据量比较小(10^6以内),用cincout 或者scanfprintf 都行;
  • 如果输入的数据量比较大(10^9左右),更推荐使用scanfprintf ,避免因为输入输出的开销,导致代码超时;
  • 在大多数场景下printf/scanfcin/cout 的使用根据个人习惯进行选择即可。

这里我们讨论了scanf/printfcin/cout 性能的差异,我们知道scanf/printf 是更快的,其实有一些极端情况下,输入输出的规模非常大的时候,scanfprintf 也不能满足的时候,会使用快速读写的方式(后续更新)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值