您的位置:首页 > 编程语言 > C语言/C++

C++重载输入和输出操作符以及IO标准库中的刷新输入缓冲区残留字符问题

2013-10-09 08:40 741 查看


C++重载输入和输出操作符以及IO标准库中的刷新输入缓冲区残留字符问题

分类: c++2013-10-08
16:25 60人阅读 评论(0) 收藏 举报

c++IO库

今天在做C++ Primer习题的14.11时,印象中应该挺简单的一题,结果却费了很长时间。
类定义:

[cpp] view
plaincopy

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;

};

重载输出操作符很简单:

[cpp] view
plaincopy

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;

}

重载输入操作符复杂一点,因为我们要考虑用户输入错误的情况:

[cpp] view
plaincopy

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;

}

之所以费了很长时间,主要因为前面少写了一行代码:

[cpp] view
plaincopy

in.ignore(INT_MAX,'\n');

[cpp] view
plaincopy

导致后面的getline得到的是空行。

为什么要加上这样一行,我在注释中已经写明了原因。以前一直以为"cin>>whatever_data"这类输入语句,碰到换行或是空白这些分隔符的时候,会在流缓冲中去除有效输入后的下一个分隔符,原来这些分隔符都还在保存在缓冲中!输入语句的行为应该是这样,只会在流中消除在它要的有效输入的前面的分隔符字符,得到想要的输入后,后面又碰到一个分隔符,说明该输入数据结束。但不对想要的输入数据后面的分隔符做任何处理

不仅是对分隔符,对于输入错误时,"cin>>.."语句在输入终止后,使输入错误的字符让保留在流缓冲区内,这是一定要用cin.ignore来清理。
8.2节中的例子:

[cpp] view
plaincopy

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函数和测试用例:

[cpp] view
plaincopy

/*

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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: