『c++读入与输出的探索』

版权声明:随你转载,你开心就好(记得评论和注明出处哦) https://blog.csdn.net/Prasnip_/article/details/81104488

对于读入与输出的探索和优化
·cin和cout
·scanf和printf
·关闭同步流
·freopen和fclose
·整型read
·浮点型与字符串read
·快输
·fread


<更新提示>

<第一次更新>


<正文>

cin和cout

cin和cout是c++自带的文件输入输出流,在<iostream>头文件中。可以用于变量的输入与输出。对于一般的变量,cin和cout可以直接使用,其表达式如下:
cin>>(表达式)>>(表达式)>>...;
cout<<(表达式)<<(表达式)<<...;
例如:
cin>>a>>b;
cout<<c;
这就是输入和输出的两个例子。
对于cin,它会自带过滤掉空格和换行,自动寻找。
对于cout,我们可以使用endl控制符进行换行操作:cout<<endl的功能就是输出一个换行。
对于浮点类型的保留小数输出,我们需要对cout进行定义操作,首先,需要头文件<iomanip>
我们有两种定义类型:科学记数法和一般小数点格式。我们只需在程序输出前增加一个语句即可:
cout<<setiosflags(ios:fixed)<<setprecision(n);
cout<<steiosflags(ios:scientific)<<srtprecision(n);
它们代表的含义是在输出浮点型时保留n位小数,前者为一般小数格式,后者为科学记数法格式。平常使用时根据题目要求在n处填一个数字,就保留了几小数。在设置这两个语句后,之后使用的所以cout语句就会执行保留小数的命令。当然,可以再写这两个语句在重新设置。
我们还可以利用cout更格式化的输入输出。
cout.width(n)
cout.fill(' ')
这两个语句代表在输出是右对齐,长度为n,不足的部分用空格补足。当然,n由你决定,空格也可以对应的替换为其他的字符。但是这两行代码在每一次输出前都要调用。
cin是有返回值的函数,如果读入了正常的数据,其返回值为1,反之,其返回值为0。因此我们可以用形如while(cin>>a>>b)的语句持续输入。

scanf和printf

scanf和prinf是c++的标准输入输出,它们在头文件<cstdio>中。对于不同类型的数据,需要有不同的格式,其大体格式如下:
scanf("格式符",&对应格式符变量);
printf("字符串与格式符",对应格式符的变量);
简单的说,scanf的用法在函数的第一个逗号前的引号里输入格式符,在逗号后输入取地址符及变量名,就可以将对应格式的数据读入到变量中。
我们常用的格式符如下:

%d 整型(int)
%lld 长整型(long long)
%c 字符(char)
%s 字符串(string或char[])
%f 实数(float)
%lf 实数(double)

举个例子:
scanf("%d%lf",&a&b);
就是将一个整型数据输入到变量a中,接着将一个double类型的实数数据输入到变量b中。其他的格式符也可以类比着理解。
不过,在使用scanf的时候要注意在变量前加上取地址符(&)。
printf的用法与scanf基本相同,只是不需要加上取地址符(&)。
在print发中,我们可以直接在引号中输入特定的字符(串),然后和变量一同输出,类似于python的元组操作。
printf("小明今年%d岁了",a);
这句的意思就是输出引号中的话,遇到格式符是,以逗号后的变量一一替换。当a=10时,这个语句就输出了“小明今年10岁了”这句话。
printf还有一些其他的输出操作。例如:在输出小数时,在格式符与百分号(%)间加形如.n的数,意为保留几位小数。
printf("%.4lf",c);,这个语句就输出了保留4位小数的实数变量c。
还有一些如上添加方法的修饰符如下:

%5d //5位数,右对齐。不足用空格补齐,超过按实际输出
%05d//5位数,右对齐。不足用0补齐,超过按实际输出
%+d//无论正负,输出符号

scanf也是有返回值的函数,其返回值为成功读取的变量个数。无输入时,其返回值为”EOF”。所以,我们用形如while(scanf("%d%d",&a&b)!="EOF")的语句来持续输入。
别看scanf和printf的规则比cin和cout多很多,它们也有自己的优点:读入速度快。在数据量大时,使用它们速度会大大提升。

关闭同步流

cin和cout为什么比scanf和printf慢这么多呢?其实时因为它在输入时不断在同步。我们可以在输入前加入ios::sync_with_stdio(false)一句关闭它的同步,就能和scanf和printf一样快了。

freopen和fclose

freopen和fclose是文件输入输出的函数,将输入输出的设备跟改为文件。其使用方法如下:

int main()
{
    freopen("xxx.in","r",stdin);
    freopen("xxx.out","w",stdout);
    //Do soemthing
    fclose(stdin);
    fclose(stdout);
    return 0;
}

我们在xxx的位置输入我们需要的文件名,就能从指定的.out文件读入数据,将数据输出到制定的.in文件中。当然,在程序中,我们依然用以前的方式输入输出(用cin,cout,scanf,printf等函数)。注意了,输入和输出的文件和cpp文件应该在同一目录下。

整型read

在某些输入数据极大的题目中,尽管关闭了同步流或使用了scanf与printf。有时输入的效率仍然不尽人意。
我们需要一种更高效率的读入方案,于是快读产生了。以下,我将介绍读入输出的优化方式
如下是一个整型快读函数的模板:

inline void read(int &k)
{
    int x=0,w=0;char ch;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    k=(w?-x:x);return;
}

快读的原理就是逐位读字符,然后将其转换,合成为一个整数。其中isdigit()函数的功能是返回字符是否是一个数字字符,isdigit(ch)相当于(ch>='0'&&ch<='9')。其他的就是一些位运算。相信知道位运算的理解快读都不难。
那么,我们在使用是只需类似于read(a)的调用,数据就读入到了变量a中。
当然,长整型也是可以逐位读入的,需要时将函数改为:

inline void read(long long &k)
{
    long long x=0,w=0;char ch;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    k=(w?-x:x);return;
}

即可,使用方法相同。

浮点型与字符串read

整型变量可以用快读,那么浮点型和字符串是否可以用快读呢?答案当然是可以的。以下是一个double类型的快读模板,其大体思路与普通快读相同,使用方式也与普通快读相同。

inline void double_read(double &k)
{
    double X=0,Y=1.0; int w=0; char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) X=X*10+(ch^48),ch=getchar();
    ch=getchar();//读入小数点
    while(isdigit(ch)) X+=(Y/=10)*(ch^48),ch=getchar();
    k=(w?-X:X);return;
}

直接用这种快读方法去读字符串当然也是可行的。

inline void read(string &s1)
{
    char ch=getchar();
    st1="";
    while(!((ch>='a')&&(ch<='z')))ch=getchar();
    while((ch>='a')&&(ch<='z')) st1+=ch,ch=getchar();
    return;
}

快输

其实快读多用于暴力程序的节省时间,如果你能打出正解,一般使用普通读入也是没有问题的。但在暴力时,追求高分就要追求的极致嘛。
快输也是一种输出提速的方法。其核心原理与快读相同:利用putchar函数逐位输出。
以下为整型快速输出模板代码。

void write(int x)
{
    int y=10,len=1;
    while(y<=x) y*=10,len++;
    while(len--){y/=10,putchar(x/y+48),x%=y;
}

fread

快速读入的极限——fread。在输入数据量大于106的题目中,输出将会占用大量的时间。如果你的程序较为复杂,时间常数较大,可能会遇到卡常数的坎。那fread就是你夺回AC的神器。
fread的输入原理时优化普通快读。我们利用fread函数直接整块读入字符串,以优化getchar()函数一个一个读入的慢速缺点。这样,我们再利用之前的快读函数,就能实现最快效率的读入。
注意,fread需要再大量数据读入时才有显著的效果。在使用fread方法后,getchar和scanf函数就都不能用了,所有读入都要自己写,许多字符和字符串操作会出现问题。所以,fread方法适用于极大输入数据,不涉及字符操作的题目,请谨慎使用。
一个a*b程序的代码如下:

#include<bits/stdc++.h>
using namespace std;
inline char Getchar()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &k)
{
    int x=0,w=0;char ch;
    while(!isdigit(ch))w|=ch=='-',ch=Getchar();
    while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=Getchar();
    k=(w?-x:x);return;
}
int main() 
{
    int a,b;
    read(a),read(b);
    cout<<a*b<<endl;
}

注意fread方法在平常运行时会特别慢,在调试程序时不建议使用,在调好程序,确定无误后可以加入程序。在评测时就不会出现这种情况,才能真正发挥作用。在确认提交前,也注意检查buf数组的大小,根据题目要求的数据大小开就行了,不要开太大。


<后记>


<废话>

猜你喜欢

转载自blog.csdn.net/Prasnip_/article/details/81104488