C++重载输入和输出操作符以及IO标准库中的刷新输入缓冲区残留字符问题
2013-10-08 16:25
567 查看
今天在做C++ Primer习题的14.11时,印象中应该挺简单的一题,结果却费了很长时间。
类定义:
重载输出操作符很简单:
重载输入操作符复杂一点,因为我们要考虑用户输入错误的情况:
之所以费了很长时间,主要因为前面少写了一行代码:
为什么要加上这样一行,我在注释中已经写明了原因。以前一直以为"cin>>whatever_data"这类输入语句,碰到换行或是空白这些分隔符的时候,会在流缓冲中去除有效输入后的下一个分隔符,原来这些分隔符都还在保存在缓冲中!输入语句的行为应该是这样,只会在流中消除在它要的有效输入的前面的分隔符字符,得到想要的输入后,后面又碰到一个分隔符,说明该输入数据结束。但不对想要的输入数据后面的分隔符做任何处理。
不仅是对分隔符,对于输入错误时,"cin>>.."语句在输入终止后,使输入错误的字符让保留在流缓冲区内,这是一定要用cin.ignore来清理。
8.2节中的例子:
不仅是C++的标准IO库,C中的标准IO库也用同样的问题——如果在scanf后面直接调用getline,也会得到空行。而且,对应cin.ignore(),可用fflush(stdin)来刷新缓冲区。
那哪些输入函数会自动处理有效输入后的换行符呢?
getline和fgets这类以行为单位的输入函数,会自动将已输入行的换行符从输入缓冲中去除。
这个教训再次告诉我们,使用函数接口的时候,一定要理清它们的行为细节。有时还要弄清它们的底层实现,才能更好地理解它们的行为。
最后给出main函数和测试用例:
类定义:
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标准库中的刷新输入缓冲区残留字符问题
- C++重载输入和输出操作符以及IO标准库中的刷新输入缓冲区残留字符问题
- 【C++重载输入和输出操作符以及IO标】
- C++中cout/cin对于空指针、字符指针的处理,及输入>>、 输出<<操作符的重载
- c++ 重载 >>(输入) 、<< (输出) 操作符
- 第十四周 阅读项目 C++字符创的标准输入输出
- C++输入操作符>> 输出操作符<<重载
- 关于流和缓冲区的理解以及一般标准输入问题的解决方法小结
- 关于流和缓冲区的理解以及一般标准输入问题的解决方法小结
- 关于流和缓冲区的理解以及一般标准输入问题的解决方法小结.
- c++ 重载 >>(输入) 、<< (输出) 操作符
- c++ 重载 >>(输入) 、<< (输出) 操作符
- 关于流和缓冲区的理解以及一般标准输入问题的解决方法小结 (fflush() setbuf() )
- c++输入和输出操作符重载
- C++学习基础八——重载输入和输出操作符
- 关于流和缓冲区的理解以及一般标准输入问题的解决方法小结
- java.io.Console的使用以及重定向标准输出/输入
- 关于流和缓冲区的理解以及一般标准输入问题的解决方法小结.
- 【C++面向对象】输入输出操作符的重载
- C/C++-标准输入/输出重定向为文件输入/输出