C++输入输出总结

在学习C/C++编程,经常会忽略I/O的使用,之前也没有自己做一遍总结。导致后来吃了不少亏,比如开发的时候,会因为忘记cin的某个成员而去查谷歌/百度,导致效率下降。今天,要好好沉思一下,写一篇总结。

特别的本文着重针对std::cin,std::cout这两个对象,和iostream流的记录,可能会穿插一点细节,但不会多。

输入流对象std::cin

平时我们使用的cin,cout,其实是命名空间中的std中声明的一个io类对象。

输入流与输入设备(键盘,串口,麦克风)相关联,外部设备的数据流向内存,cin则负责从输入流中对数据进行读取,提取操作。含有输入的程序都会建有一个输入缓冲区。当我们外部设备输入数据时,数据会先存储到输入缓冲区中,然后cin对象在从输入缓冲区中读取数据,因此如果某次cin读取数据后,缓冲区还有未读取的残留数据的话,再次执行cin读取的话,cin会直接取走缓冲区剩下的数据,而不会请求键盘输入,这也是很多时候会遇到的莫名其妙cin不按预计的逻辑去请求键盘输入的原因。

cin>>

cin最简单的使用方法就是使用>>直接获取键盘输入

int num1,num2;
cin>>num1>>num2; //输入两个数字
cin>>str;//输入字符串

cin>>方法的结束条件:遇到回车 空格 Tab键

结束处理:丢弃缓冲区中上述三种结束符号。
测试:

char str[10];
cin>>str;
cout<<str<<endl;
cin>>str;
cout<<str;

输入例子:
1. abcd efgh
2. abcd 中间回车隔断,这个好理解,输出就不显示了
efgh
3. abcd efgh 中间是tab

例子输出:
1.
abcd
efgh
3.
abcd
efgh

结果分析:上面的1,3的例子都是输入完后,程序直接结束,第一次读取时,str只读取了前面的abcd,然后输出abcd,在换行;
第二次读取没有请求键盘输入,str丢弃了中间的结束符(回车,空格,tab键),直接读取缓冲区剩余的efgh并且覆盖掉abcd,然后输出efgh。

cin.get(接收数据数组名,长度,结束符号)

cin.get()方法可以制定我们读取内容时的结束符号(可选,默认为回车),但并不会在缓冲区中丢弃这个结束符。读取的字符个数为(长度-1)个,这个需要注意。
如果要读取一个字符,可以调用无参的重载版本。

测试1 使用默认结束符(回车):
char str[10];
cin.get(str,10);
cout<<str;

输入例子:
1. abcd efgh //空格
2. abcd efgh //tab

例子输出:
1. abcd efgh
2. abcd efgh

结果分析:因为默认的结束符是回车,所以tab和空格都被保留了下来

测试2 定制默认结束符为c
char str[10];
cin.get(str,10,'c');
cout<<str<<endl;
cin.get(str,10);//使用默认回车做结束符
cout<<str;

输入例子:
1. abcd efgh //空格
2. abcd efgh //tab

例子输出:
1.
ab //空格
cd efgh
2.
ab
cd efgh //tab

结果分析:第一次读取时,c为结束符,所以第一行输出ab,第二行使用默认的回车结束符,因为没有丢弃c,所以第二行的第一个输出是c。

那对于默认结束符回车是否会丢弃呢?

测试3 检验时候会丢弃回车
读取字符串
char str[10];
char c1;
cin.get(str,5);//读取4个字节
c1=cin.get();
cout<<(int)str[4]<<" "<<(int)c1;

输入例子:
1. abcd[enter] //按下enter,后windows下会输入回车换行(\r\n)两个符号
2 abcde
例子输出:
1. 0 10(换行的十进制ASCII码)
2. 0 101(e的十进制ASCII码)

结果分析:第一个输入,因为只读取4个字节,所以str[4]为’/0’,而后面输出10,是因为丢弃了回车符,换行符没有被丢弃。所以输出的是10(换行符)而不是13(回车符)。
第二个输入则很明了了。

结论:读取字符串时,会丢弃回车符,保留换行符。

读取字符

程序还是上面那个,只不过输出str[1]
输入例子:
1. a[enter]
例子输出:
1. 0 10

结果分析:还是会丢弃回车符

结论:cin.get()会丢弃缓冲区中的默认结束符(回车),而不会丢弃自定义的符号,经测试如果把自定义结束符设置为\r,也会把\r进行丢弃,建议自行debug,查看内存。

cin.getline(读取数组名,长度,结束符)

getline的参数和cin.get()差不多,同样默认的使用回车作为结束符,getline顾名思义是专门为按行读取应用而准备的一个方法。
区别在于,cin.getline()读取超长的数据,会引起错误,使得cin的一些标志错误流的位被置位,然后后续cin无法正常工作。

流发生错误的例子
char str[10];
char c1;
cin.getline(str,5);//读取4个字节 
cout<<str;//输出 
cin>>str;//再次读取 
cout<<str<<endl;//输出 

输入例子:
1. abcdefgh
2. abcd efgh

例子输出:
1. abcdabcd
2. abcdabcd

结果分析:上述两个例子都是连续输出两次abcd,流并没有去读取缓冲区的剩余内容。因为第一次getline读取了过多字符,引起流出现了错误,而没有正常工作,所以第二次输出的是上次的内容abcd。

getline的正确用法,只用来读取行
    char str[10];
    char c1;
    cin.getline(str,10);//读取9个字节 
    cout<<str;//输出 
    cout<<(int)str[6]<<endl; 
    cin>>str;
    cout<<(int)str[0]; 

输入例子:
1. abcd

例子输出:
1. abcd0

结果分析:cin读取了一行,并且丢弃了换行符号。

cin.eof()

cin.eof()使用来检车是否有来自键盘输入的ctrl+z来中断程序,用户中断程序或者读取文件完毕输入流的eofbit会置位然后函数返回true,一般是用来判断输入是否结束。
一般用法:

while(!cin.eof())
{
 //do something
}
cin.clear()和cin.sync()方法

cin.clear()用来回复输入流的各标志位到缺省状态。如果cin流出现错误了,调用clear方法后,流会重新正常工作。
sync()方法用来清除缓冲区中残余的数据流。清除缓冲区的数据流,并不会改变流中的。
一般两者结合一起来使用。
先恢复位流标志位,在进行缓冲区清除。

cin.ignore(最大输入数量,忽略字符)

顾明思义,该方法会根据两个参数来丢弃缓冲区中的数据,当丢弃字节数量到达最大输入数量或者遇到忽略字符时,cin.ignore()函数执行返回。一般只用来消除上一次输入对下一次输入的影响。
一般用法:

cin.ignore(100,'\n')

上述例子会忽略输入前100个字节,或者回车换行(包括回车换行)之前的内容,两个参数冲突的时候,丢弃规则以第一个参数为准(比如:cin.ignore(2,c),输入:abcde,会输出:cde)。

一般使用会把第一个参数设置的很大,在程序阅读上表明只让第二个参数起作用,个人也建议只让第二个参数起作用。

输入流暂时说到这里。

输出流对象std::cout

输出流能说的东西就比较多了。输出流和输入流一样有一个输出缓冲区,每次使用cout,cout会把数据写入输出缓冲区,然后相应的输出设备会在缓冲区中拿走数据。

cout<<

这个最普通的输出也不用多说什么了

流控制算子

C语言中我们可以使用%d,%f等来控制输出数据的格式,还可以通过%x,%o来控制输出的进制。

而在C++中采用一系列流控制算子来控制

基本算子如下:

无参算子  iostream
可用于输入时设置
    dec           //十进制
    oct           //八进制
    hex           //16进制
    endl          //换行
    flush          //立即输出(清空流)
有参算子      iomanip
    resetiosflags(long)   //清除标志位
    setfill(int)      //设置填充字符
    setiosflags(long)    //设置标志位
    setprecision(int)    //设置精度,有效数字
    setw(int)        //设置宽度

使用如下:

    char str[]="a b c d e f g h"; //输出结果看图①
    int  str[]={252,253,254,255}; //输出结果看图②
    cout<<"16进制输出:"; 
    cout<<hex;
    for(int i=0;i<sizeof(str)/sizeof(*str);i++)
    {
        cout<<"0x"<<(int)str[i]<<" ";
    }

    cout<<endl<<"8进制输出:"; 
    cout<<oct;
    for(int i=0;i<sizeof(str)/sizeof(*str);i++)
    {
        cout<<(int)str[i]<<" ";
    }

    cout<<endl<<"10进制输出:"; 
    cout<<dec;
    for(int i=0;i<sizeof(str)/sizeof(*str);i++)
    {
        cout<<(int)str[i]<<" ";
    }

控制符一次设置后即有效,但是要注意上述三个进制控制输出符号只对整形数有效,如果要输出字符的16进制则需要将其强制转换成整形数。

这里写图片描述
图①

这里写图片描述
图②

好了暂时就记录到这里。

更多的使用可以参考下面的博文
http://www.2cto.com/kf/201604/501799.html

http://www.xuebuyuan.com/263070.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值