I’ve singled out a failure on my program that prevents me from assigning a value to the variable addAntonymAnswer1. I’ve tried running cin.clear() before the statement to get the thing read my yes/no answer, but the code just won’t respond.
The program bit that’s failing is located inside void dictionaryMenu(vector <WordInfo> &wordInfoVector) and reads
cin.clear(); cout<<'>'; cin>>addAntonymAnswer1; // cin reading STUCK, why!?
to get to that point of the program the user has to choose to add a word, and then add a synonym.
The input for running the program is:
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's 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's 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; }
cin.clear()doesn’t clear the standard input. What it does is clearing error bits, likeeofbit,failbitand others, and sets the stream into a good state. Maybe you expected it to clear out anything in it? If the user typedJust before, and you
It will read up to
noand the stream will still containThe call to
clearthen clears any error bits being active. Then, yourWill read the
nothat wasn’t eaten by the previous read, and the action immediately returns, not waiting for new input. What you should do is doing aclearfollowed by an ignore, up to the next newline. You tell it the amount of characters it should ignore maximally. That amount should be the highest number possible:Doing that will make the stream empty, and a following read will wait for you to type something in.
Another problem arises if you have got a
cin >>followed by agetline: The cin will leave any whitespace (also newlines) after its read token, butgetlinewill stop reading after it hits such a newline. I see you have putclearafter nearly everything. So i want to show you when you need it and when not. You don’t need it when you sequence multiplecin >>. Assume you have in your buffer: ‘foo\nbar\n’. Then you do the following readsAfter the first, your buffer will contain ‘\nbar\n’. That is, the newline is still in. The second
cin>>will first skip all whitespace and newlines, so that it can cope with\nbeing at the front ofbar. Now, you can also sequence multiplegetlinecalls:Getline will throw away the
\nthat it reads at the line end, but won’t ignore newlines or whitespace at the begin. So, after the first getline, the buffer contains ‘bar\n’. The second getline will correctly read ‘bar\n’ too. Now, let’s consider the case where you need the clear/ignore:The first will leave the stream as ‘\nbar\n’. The getline then will see immediately the
\nat the begin, and will think it read an empty line. Thus, it will immediately continue and not wait for anything, leaving the stream as ‘bar\n’. So, if you have agetlineafter acin>>you should first execute the clear/ignore sequence, to clear out the newline. But betweengetlineorcin>>‘s, you should not do it.