Why is this cin reading jammed?

I highlighted an error in my program that prevents me from assigning a value to the addAntonymAnswer1 variable. I tried running cin.clear() before the operator read my yes/no answer, but the code just won't respond.

A program bit that does not work is inside the void dictionaryMenu(vector <WordInfo> &wordInfoVector) and reads

  cin.clear(); cout<<">"; cin>>addAntonymAnswer1; // cin reading STUCK, why!? 

To get to this point in the program, the user must select add a word, and then add a synonym.

Input to start the program:

 dictionary.txt 1 cute 2 hello 3 ugly 4 easy 5 difficult 6 tired 7 beautiful synonyms 1 7 7 1 3 2 antonyms 1 3 3 1 7 4 5 5 4 7 3 

 #include <iostream> #include <fstream> #include <string> #include <sstream> #include <vector> using namespace std; class WordInfo{ public: WordInfo(){} WordInfo(string newWord){ word=newWord; } ~WordInfo() { } int id() const {return myId;} void readWords(istream &in) { in>>myId>>word; } vector <int> & getSynonyms () { return mySynonyms; } vector <int> & getAntonyms() { return myAntonyms; } string getWord() { return word; } void dictionaryMenu (vector <WordInfo> &wordInfoVector){ cout<<endl<<"Would you like to add a word?"<<endl; cout<<"(yes/no)"<<endl; cout<<">"; string addWordAnswer; cin>>addWordAnswer; if (addWordAnswer=="yes") // case if the guy wants to add a word { cout<<endl; cout<<"Please, write the word "<<endl; string newWord; cout<<">"; cin>>newWord; cout<<endl; WordInfo newWordInfo (newWord); int newWordId = wordInfoVector.size() +1; newWordInfo.myId=newWordId; cout<<"The id of "<<newWordInfo.word<<" is "<<newWordInfo.myId<<endl<<endl; wordInfoVector.push_back(newWordInfo); cout<<"Would you like to define which words on the existing dictionary are" <<endl <<"synonyms of "<<newWordInfo.word<<"?"<<endl; cout<<"(yes/no)"<<endl; string addSynonymAnswer, addAntonymAnswer1, addAntonymAnswer2; cout<<">"; cin>>addSynonymAnswer; if (addSynonymAnswer=="yes") { cout<<endl; cout<<"Please write on a single line the ids for the synonyms of " <<newWordInfo.word<<endl<<"starting with its id, which is "<<newWordInfo.myId<<endl<<endl; cout<<"For example, to define that the synonym of the word 'cute', which has an id 1, is" <<"'beautiful', which has an id 7, you should write: 1 7"<<endl<<endl; cout<<"In the case of "<<newWordInfo.word<<" you should start with "<<newWordInfo.myId<<endl; cin.clear(); string lineOfSyns; cout<<">"; cin>>lineOfSyns; newWordInfo.pushSynonyms(lineOfSyns, wordInfoVector); cin.clear(); cout<<"Would you like to define which words on the existing dictionary are" <<endl <<"antonyms of "<<newWordInfo.word<<"?"<<endl; //##HERE THE CIN READING OF addAntonymAnswer1 FAILS, WHY? cin.clear(); cout<<">"; cin>>addAntonymAnswer1; // cin reading STUCK, why!? if (addAntonymAnswer1=="yes"){ } else if (addAntonymAnswer1=="no"){ // END DICTIONARY MENU } } else if (addSynonymAnswer=="no"){ cout<<"Would you like to define which words on the existing dictionary are" <<endl <<"antonyms of "<<newWordInfo.word<<"?"<<endl; cout<<">"; cin>>addAntonymAnswer2; if (addAntonymAnswer2=="yes"){ } else if (addAntonymAnswer2=="no"){ // END DICTIONARY MENU } } } // if addWordAnswer == "no" else if (addWordAnswer=="no"){ // ######RETURN TO MAIN MENU############ } } void pushSynonyms (string synline, vector<WordInfo> &wordInfoVector){ stringstream synstream(synline); vector<int> synsAux; // synsAux tiene la línea de sinónimos int num; while (synstream >> num) {synsAux.push_back(num);} int wordInfoVectorIndex; int synsAuxCopyIndex; if (synsAux.size()>=2){ // takes away the runtime Error for (wordInfoVectorIndex=0; wordInfoVectorIndex <wordInfoVector.size(); wordInfoVectorIndex++) { if (synsAux[0]==wordInfoVector[wordInfoVectorIndex].id()){ // this is the line that generating a Runtime Error, Why? for (synsAuxCopyIndex=1; synsAuxCopyIndex<synsAux.size(); synsAuxCopyIndex++){ // won't run yet wordInfoVector[wordInfoVectorIndex].mySynonyms.push_back(synsAux[synsAuxCopyIndex]); } } } }// end if size()>=2 } // end pushSynonyms void pushAntonyms (string antline, vector <WordInfo> &wordInfoVector) { stringstream antstream(antline); vector<int> antsAux; int num; while (antstream >> num) antsAux.push_back(num); int wordInfoVectorIndex; int antsAuxCopyIndex; if (antsAux.size()>=2){ // takes away the runtime Error for (wordInfoVectorIndex=0; wordInfoVectorIndex <wordInfoVector.size(); wordInfoVectorIndex++) { if (antsAux[0]==wordInfoVector[wordInfoVectorIndex].id()){ // this is the line that generating a Runtime Error, Why? for (antsAuxCopyIndex=1; antsAuxCopyIndex<antsAux.size(); antsAuxCopyIndex++){ // won't run yet wordInfoVector[wordInfoVectorIndex].myAntonyms.push_back(antsAux[antsAuxCopyIndex]); } } } }// end if size()>=2 } //--dictionary output function void printWords (ostream &out) { out<<myId<< " "<<word; } //--equals operator for String bool operator == (const string &aString)const { return word ==aString; } //--less than operator bool operator <(const WordInfo &otherWordInfo) const { return word<otherWordInfo.word;} //--more than operator bool operator > (const WordInfo &otherWordInfo)const {return word>otherWordInfo.word;} public: vector<int> mySynonyms; vector <int> myAntonyms; string word; int myId; }; //--Definition of input operator for WordInfo istream & operator >>(istream &in, WordInfo &word) { word.readWords(in); } //--Definition of output operator ostream & operator <<(ostream &out, WordInfo &word) { word.printWords(out); } int main() { string wordFile; cout<<"enter name of dictionary file: "<<endl; getline (cin,wordFile); ifstream inStream (wordFile.data()); if(!inStream.is_open()) { cerr<<"cannot open "<<wordFile<<endl; exit(1); } vector <WordInfo> wordInfoVector; WordInfo aword; while (inStream >>aword && (!(aword=="synonyms"))) { wordInfoVector.push_back(aword); } inStream.clear(); vector <int> intVector; string synLine; while (getline(inStream, synLine)&&(synLine!=("antonyms"))){ aword.pushSynonyms(synLine, wordInfoVector); } int theIndex; string antLine; while (getline(inStream,antLine)){ aword.pushAntonyms(antLine, wordInfoVector); } cout<<endl<<"the words on the dictionary are: "<<endl; int h=0; while (h<wordInfoVector.size()){ cout<<wordInfoVector[h]<<endl; h++; } aword.dictionaryMenu(wordInfoVector); system("PAUSE"); return 0; } 
+2
source share
4 answers

cin.clear() does not clear standard input. It cleans up error bits such as eofbit , failbit and others, and sets the stream to a good state. Maybe you expected him to take away something in him? If the user typed

 yes no 

Just before that, and you

 cin >> someStringVariable; 

It will read to no , and the stream will contain

  no 

The clear call then clears any error bits that are active. Then,

 cin>>addAntonymAnswer1; 

Will read no , which was not eaten by the previous reading, and the action returns immediately, without waiting for a new entry. What you need to do is make clear , followed by ignoring, up to the next new line. You specify the number of characters that should be ignored as much as possible. This amount should be as high as possible:

 cin.clear(); cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 

Doing this will cause the stream to be empty and the next read will wait for the type to be entered.


Another problem arises if you have cin >> followed by getline : cin will leave any spaces (also new lines) after its read token, but getline will stop reading after it gets on such a new line. I see that you put clear after almost everything. Therefore, I want to show you when you need it and when not. You do not need this when you are doing a few cin >> . Suppose you have in your buffer: "foo \ nbar \ n". Then you do the following readings

 cin >> a; // 1 cin >> b; // 2 

After the first, your buffer will contain "\ nbar \ n". That is, a new line is still located. The second cin>> first skip all spaces and newlines so that it can handle the \n at the beginning of bar . Now you can also make several getline calls:

 getline(cin, a); getline(cin, b); 

Getline throws \n which it reads at the end of the line, but will not ignore newlines or spaces at the beginning. So, after the first getline, the buffer contains "bar \ n". The second line of getline will read "bar \ n" correctly. Now consider the case where you need clear / ignore:

 cin >> a; getline(cin, b); 

The first will leave the stream as "\ nbar \ n". Then getline will immediately see \n at the beginning and will assume that it is reading an empty line. Thus, it will continue immediately and wait for nothing, leaving the stream "bar \ n". So, if you have getline after cin>> , you must first run the clear / ignore sequence to clear the new line. But between getline or cin>> 's you shouldn't do this.

+13
source

He is "stuck" because he is waiting for input. cin is tied to the standard input descriptor for the program, you need to enter something and press enter.

+1
source

cin >> ... is read from standard input until it finds a whitespace character. When you enter, say, 8 5 for the list of synonyms, 8 read in lineOfSyns and nothing more. When the program reaches cin >> addAntonymAnswer1 , 5 read in addAntonymsAnswer1 . Your program behaves unexpectedly, since it expects yes or no , but it received 5 .

Look at using cin.getline() instead of >> . See, for example, sections 18.2 and 18.3 on this page .

+1
source

In your program, you ask the user:

 Please write on a single line the ids for the synonyms of test starting with its id, which is 8 For example, to define that the synonym of the word 'cute', which has an id 1, i s'beautiful', which has an id 7, you should write: 1 7 In the case of test you should start with 8 

Then you try to read in the line that the user entered with

 cin>>lineOfSyns; 

However, this is only a reading up to the first space. So the second number entered by the user is still in the cin buffer when

 cin>>addAntonymAnswer1; 
Running line

therefore, the data is read into the addAntonymAnswer1 line. The user never gets the option to enter yes or no, and your tests for these values ​​fail.

You should consider changing to using the string overload for getline() to read:

 getline( cin, stringvar); 

This will probably be better than using cin.getline() since it does not have an overload that accepts string - with this member function, you need to read an array of characters that is much less flexible than reading in string .

+1
source

Source: https://habr.com/ru/post/1442561/


All Articles