zoukankan      html  css  js  c++  java
  • 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 '
    ' character still in the input stream buffer.
    		in.ignore(INT_MAX,'
    ');
    		//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,'
    ');
    导致后面的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;
    }
    


     

  • 相关阅读:
    Java Bean validation specification...
    javascript压缩工具:YUI compressor
    CSS: Float a div on another div, Ex: Text caption on picture
    汉文博士 0.5.3.1944 测试版发布
    简单记事本程序java源码项目
    Windows计算机功能Java源码
    HighCharts 图表插件 自定义绑定 时间轴数据
    Windows Phone 8.1 新特性
    可自定义导航条功能案例ios项目源码
    自动计算尺寸列表功能案例ios源码
  • 原文地址:https://www.cnblogs.com/james1207/p/3358101.html
Copyright © 2011-2022 走看看