C++重载输入和输出操作符以及IO标准库中的刷新输入缓冲区残留字符问题
今天在做C++ Primer习题的14.11时,印象中应该挺简单的一题,结果却费了很长时间。
类定义:
typedef string Date; class CheckoutRecord{
public:
CheckoutRecord(){book_id=-1;}
friend ostream& operator<<(ostream &os,const CheckoutRecord &obj);
friend istream& operator>>(istream &in,CheckoutRecord &obj);
private:
double book_id;
string title;
Date date_borrowed;
Date date_due;
pair<string,string> borrower;
vector<pair<string,string>*>wait_list;
};
重载输出操作符很简单:
ostream& operator<<(ostream &os,const CheckoutRecord &obj)
{
os<<"Book ID:"<<obj.book_id<<endl;
os<<"Title :"<<obj.title<<endl;
os<<"Data borrowed:"<<obj.date_borrowed<<endl;
os<<"Date due :"<<obj.date_due<<endl;
os<<"Borrower :"<<obj.borrower.first<<" "<<obj.borrower.second<<endl;
os<<"Waiters for this book:"<<endl;
for(unsigned int i=0;i<obj.wait_list.size();++i)
os<<obj.wait_list[i]->first<<" "<<obj.wait_list[i]->second<<";";
os<<endl;
return os;
}
重载输入操作符复杂一点,因为我们要考虑用户输入错误的情况:
istream& operator>>(istream &in,CheckoutRecord &obj)
{
in>>obj.book_id;
if(in){
//when you typed newline,the new line was added to the
//stream buffer, but "in>>obj.book_id" only reads the first double data and
// left '\n' character still in the input stream buffer.
in.ignore(INT_MAX,'\n');
//Title may contain spaces
std::getline(in,obj.title); in>>obj.date_borrowed>>obj.date_due>>\
obj.borrower.first>>obj.borrower.second; while(in){
pair<string,string> *waiter=new pair<string,string>;
in>>waiter->first;
if(waiter->first=="end"){
delete waiter;
break;
}
in>>waiter->second;
obj.wait_list.push_back(waiter);
}
}
else
obj=CheckoutRecord();
return in;
}
之所以费了很长时间,主要因为前面少写了一行代码:
in.ignore(INT_MAX,'\n');
导致后面的getline得到的是空行。
为什么要加上这样一行,我在注释中已经写明了原因。以前一直以为"cin>>whatever_data"这类输入语句,碰到换行或是空白这些分隔符的时候,会在流缓冲中去除有效输入后的下一个分隔符,原来这些分隔符都还在保存在缓冲中!输入语句的行为应该是这样,只会在流中消除在它要的有效输入的前面的分隔符字符,得到想要的输入后,后面又碰到一个分隔符,说明该输入数据结束。但不对想要的输入数据后面的分隔符做任何处理。
不仅是对分隔符,对于输入错误时,"cin>>.."语句在输入终止后,使输入错误的字符让保留在流缓冲区内,这是一定要用cin.ignore来清理。
8.2节中的例子:
int ival;
// read cin and test for only EOF; loop is excuted even if there are other IO failures
while(cin >> ival, !cin.eof()){
if(cin.bad()) // input stream is corrupted; bail out
throw runtime_error("IO stream corrupted!");
if(cin.fail()){
cerr << "Bad data, try again!";
cin.clear();
cin.ignore();
continue;
}
}
不仅是C++的标准IO库,C中的标准IO库也用同样的问题——如果在scanf后面直接调用getline,也会得到空行。而且,对应cin.ignore(),可用fflush(stdin)来刷新缓冲区。
那哪些输入函数会自动处理有效输入后的换行符呢?
getline和fgets这类以行为单位的输入函数,会自动将已输入行的换行符从输入缓冲中去除。
这个教训再次告诉我们,使用函数接口的时候,一定要理清它们的行为细节。有时还要弄清它们的底层实现,才能更好地理解它们的行为。
最后给出main函数和测试用例:
/*
Sample Input: 1001
Miserable World
201308
201309
Simon Smith
Mike a
Kris b
Tom c
Bison d
Jumping e
end err_id
Miserable World
201308
201309
Simon Smith
Mike a
Kris b
Tom c
Bis d
Jump e
end */
int _tmain(int argc, _TCHAR* argv[])
{
CheckoutRecord record;
cin>>record;
cout<<"========================================"<<endl;
cout<<record;
}
C++重载输入和输出操作符以及IO标准库中的刷新输入缓冲区残留字符问题的更多相关文章
- Intel FPGA 专用时钟引脚是否可以用作普通输入,输出或双向IO使用?
原创 by DeeZeng FPGA 的 CLK pin 是否可以用作普通输入 ,输出或双向IO 使用? 这些专用Clock input pin 是否可以当作 inout用,需要看FPGA是否支 ...
- C++学习基础八——重载输入和输出操作符
一.重载输入操作符的要点: 1.返回值为istream &. 2.第一个参数为istream &in. 3.第二个参数为自定义类型的引用对象(例如Sales_Item &ite ...
- 5.4 C++重载输入与输出操作符
参考:http://www.weixueyuan.net/view/6382.html 总结: 在C++中,系统已经对左移操作符“<<”和右移操作符“>>”分别进行了重载,使其 ...
- c++ io标准库2
转自:http://www.2cto.com/kf/201110/109445.html 接下来我们来学习一下串流类的基础知识,什么叫串流类? 简单的理解就是能够控制字符串类型对象进行输入输出的类,C ...
- 走进C++程序世界------IO标准库介绍
流概述 流是C++标准的组成部分,流的主要目标是,将从磁盘读取文件或将输入写入控制台屏幕的问题封装起来,创建流后程序猿就能够使用它.流将负责处理全部的细节. IO类库 在C++输入、输出操作是通 ...
- C++ Primer笔记10_运算符重载_赋值运算符_进入/输出操作符
1.颂值运营商 首先来福值运算符引入后面要说的运算符重载.上一节说了构造函数.拷贝构造函数:一个类要想进行更好的控制.须要定义自己的构造函数.拷贝构造函数.析构函数.当然,还有赋值运算符.常说的三大函 ...
- C++重载>>和<<(输入和输出运算符)详解
转载:http://c.biancheng.net/view/2311.html 在C++中,标准库本身已经对左移运算符<<和右移运算符>>分别进行了重载,使其能够用于不同数据 ...
- Go语言标准库_输入/输出
Go语言标准库_输入/输出 转载节选自<Go语言标准库> Reader 接口 type Reader interface { Read(p []byte) (n int, err erro ...
- Java:文件字符流和字节流的输入和输出
最近在学习Java,所以就总结一篇文件字节流和字符流的输入和输出. 总的来说,IO流分类如下: 输入输出方向: 输入流(从外设读取到内存)和输出流(从内存输出到外设) 数据的操作方式: 字节流 ...
随机推荐
- [转]C#发送Email邮件 (实例:QQ邮箱和Gmail邮箱)
下面用到的邮件账号和密码都不是真实的,需要测试就换成自己的邮件账号. 需要引用:using System.Net.Mail;using System.Text;using System.Net; 程序 ...
- 【Sqlserver】企业管理器打不开
今天,我的MMSSQL 2000突然不好用了,数据库服务器可以启动,但是企业管理器打不开了,还弹出提示信息,真是怪了,从来没有遇到这样的情况. 我以为是SQL Server的安装文件被破坏了,所以考虑 ...
- c#的协变和逆变
关于协变和逆变要从面向对象继承说起.继承关系是指子类和父类之间的关系:子类从父类继承,所以子类的实例也就是父类的实例.比如说Animal是父类,Dog是从Animal继承的子类:如果一个对象的类型是D ...
- JS基础类型和对象,分别是按值传递还是按引用传递?
在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(call by reference).在计算机科学里,这个部分叫求值策略(Evaluation Strat ...
- 51nod1212无向图最小生成树
1212 无向图最小生成树 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 N个点M条边的无向连通图,每条边有一个权值,求该图的最小生成树. Inpu ...
- mac OS X下PhpStorm+MAMP PRO+Xdebug+FireFox集成开发和断点调试环境配置
一.环境及软件 1.macbook pro 2.Phpstorm 3.MAMP PRO 4.FireFox 二.环境搭建 1.PhpStorm导入项目 下载PhpStorm并安装,网上随便找个注册码即 ...
- Delphi-仿vb里的IIF函数
//Delphi 函数-IIF // 实例-ChkValue := IIF(TCheckBox(tsPzJz.Controls[i]).Checked, '); function IIF(lExp: ...
- 概念:RPG与RPGLE的区别
RPG是OPM编程模式,即RPG编程的代码不能编译成*MODULE:编译只能直接生成一个程序,*PGM. RPGLE是ILE编程模式.OS/400环境下,ILE是集成开发环境.在ILE环境下,所 ...
- (转)Mac OS X内核编程,MAC驱动开发资源汇总
一.Mac OS X内核编程开发官方文档: I/O Kit Fundamentals: I/O Kit基础 - Mac OS X系统内核编程 https://developer.apple.com ...
- 【分享】SQL Server优化50法
虽然查询速度慢的原因很多,但是如果通过一定的优化,也可以使查询问题得到一定程度的解决. 查询速度慢的原因很多,常见如下几种: 没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) I/ ...