Infinite loop reading from stdin using cin::fail() - c++

I'm struggling with a vector push_back function.
The goal is to have a function which pushes n number of elements until you decide to stop.
So my idea of a 'stop', is cin.fail().
The faulty function is
void pushbackVector(vector<double> &data)
{
double input;
cin >> input;
for (int i = 0; i < 100; i++)
{
if (cin.fail())
{
cout << "Ending input.\n";
return;
}
else
{
data.push_back(input);
}
}
Problem is that when I attempt to use it, I enter a infinite loop.
I have yet to sort the first vector in ASC order, second in DESC order and concatenate the first and second into the third vector. However I'm confident that I can manage this on my own.
Anyway the whole code....
#include<iostream>
#include<vector>
#include<algorithm>
#include<cctype>
using namespace std;
// function prototypes
void menu();
void printVector(const vector<double> &data);
void pushbackVector(vector<double> &data);
void sortVector (vector<double> &data);
int main()
{
menu();
vector<double> row1;
vector<double> row2;
/* not yet used
vector<double> row3;
*/
int input;
cin >> input;
bool exit = 0;
while (!exit)
{
switch (input)
{
case 1:
pushbackVector(row1);
break;
case 2:
pushbackVector(row2);
break;
case 3:
printVector(row1);
break;
case 4:
printVector(row2);
break;
case 5:
cout << "Printing out the contents of row 1\n";
printVector(row1);
cout << "Printing out the contents of row 2\n";
printVector(row2);
cout << "Printing out the contents of row 3\n";
// printVector(row3);
break;
case 6:
cout << "Exitting\n";
exit = 1;
break;
default:
cout << "Invalid choice\n";
}
}
return 0;
}
void menu()
{
cout << "Choose an option\n";
cout << "1) Enter first vector\n";
cout << "2) Enter second vector\n";
cout << "3) Print out the first vector\n";
cout << "4) Print out the second vector\n";
cout << "5) Print out all three vectoros\n";
cout << "6) Exitting the program\n";
}
void printVector(const vector<double> &data)
{
for(int i = 0; i < data.size(); i++)
{
cout << data[i] << ", ";
}
cout << "\n";
}
void pushbackVector(vector<double> &data)
{
double input;
cin >> input;
for (int i = 0; i < 100; i++)
{
if (cin.fail())
{
cout << "Ending input.\n";
return;
}
else
{
data.push_back(input);
}
}
}
void sortVector (vector<double> &data)
{
cout << "Sorting your vector \n";
sort(data.begin(), data.end());
}

You're only reading once, move the read inside the loop:
void pushbackVector(vector<double> &data)
{
double input;
// cin >> input; --------------
//
for (int i = 0; i < 100; i++) //
{ //
cin >> input; // <---------
if (cin.fail())
{
cout << "Ending input.\n";
return;
}
else
{
data.push_back(input);
}
}
That'll make sure that you actually get input. Now, if you're not going to enter 100 values, you need to somehow notify the stream. That's done by insert "EOF character" in it. Press CTRL+Z on windows or CTRL+D on unix terminals.
When this gets read from the stream, it enters a fail (and eof) state and it'll stay like that unless you clear the error flags by calling cin.clear() when appropriate.
You've made the same mistake also in main. You only read once before the while loop, so input keeps the value you initialy entered and keeps entering the same choice. I think that's the infinite loop you're talking about. To fix it, move the read statement just before the switch.
Hope that helps.
Also, this is how I'd write the function:
double input;
for (int i = 0; (cin >> input) && i < 100; ++i) {
data.push_back(input);
}
cout << "Ending input.\n";
Streams can be used in boolean expression - they convert to the result of !fail() - and such are a convenient and idiomatic way to control a loop.

The infinite loop is cause by the fact that you are reading:
cin >> input;
once and then entering a while loop (in your main) that will keep going forever (unless the input is initially equal to 6).
Change:
cin >> input;
bool exit = 0;
while (!exit)
{
// ...
to:
bool exit = 0;
while (!exit)
{
cin >> input;
// ...
Depending on what your logic is, the same is happening in the pushbackVector function at:
double input;
cin >> input;
for (int i = 0; i < 100; i++)
{
// ...
You might want to change that to:
double input;
for (int i = 0; i < 100; i++)
{
cin >> input;
// ...

Do something like this instead:
void pushbackVector(vector<double> &data)
{
double input;
while (cin >> input) //will return true when there's valid input, otherwise false
{
if (input == -1)
{
cout << "Ending input.\n";
return;
}
else
{
data.push_back(input);
}
}
This will read the input until you enter -1 or enter invalid input.
I think relying on cin.fail() is just not a good idea. The proper way to use fail() is explained in the link. It is not what you may expect.

Putting aside the reading which is misplaced, if you enter something you should not, you need to purge the input.
Add in the block of te first if
cin.clear();
cin.ignore( numeric_limits<streamsize>::max(), '\n' );

I would write the function the following way
void pushbackVector( std::vector<double> &data )
{
cin.clear();
cin.ignore( std::numeric_limits<streamsize>::max(), '\n' );
data.insert( data.end(), std::istream_iterator<double>( std::cin ), std::istream_iterator<double>() );
}

I was done some days before but I forgot to post my answer.
Who knew that I could just say if the cin fails, stop the input but don't end the program, lol.
#include<iostream>
#include<vector>
#include<algorithm> // for sort algorithms
#include<iomanip> // for setprecision
using namespace std;
// function prototypes
void menu();
void printVector(const vector<double> &data);
void pushbackVector(vector<double> &data);
void sortVector (vector<double> &data);
int main()
{
vector<double> row1;
vector<double> row2;
vector<double> row3;
int input;
bool exit = false;
while(!exit)
{
menu();
cin >> input;
switch (input)
{
case 1:
cout << "Entering vector 1\n";
pushbackVector(row1);
sortVector(row1);
cout << "\n";
break;
case 2:
cout << "Entering vector 2\n";
pushbackVector(row2);
sortVector(row2);
reverse(row2.begin(), row2.end());
cout << "\n";
break;
case 3:
cout << "Printing out vector 1\n";
printVector(row1);
cout << "\n";
break;
case 4:
cout << "Printing out vector 2\n";
printVector(row2);
cout << "\n";
break;
case 5:
// reserve enough space for all of row1's and row2's elements
row3.reserve(row1.size() + row2.size());
// insert row1's elements at the end of row3
row3.insert(row3.end(), row1.begin(), row1.end());
// insert row2's elements at the end of row3
row3.insert(row3.end(), row2.begin(), row2.end());
cout << "Printing out the contents of vector 1\n";
printVector(row1);
cout << "Printing out the contents of vector 2\n";
printVector(row2);
cout << "Printing out the contents of vector 3\n";
printVector(row3);
cout << "\n";
break;
case 6:
cout << "Exitting\n";
exit = true;
break;
default:
cout << "Invalid choice\n";
}
}
return 0;
}
void menu()
{
cout << "Choose an option\n";
cout << "1) Enter first vector\n";
cout << "2) Enter second vector\n";
cout << "3) Print out the first vector\n";
cout << "4) Print out the second vector\n";
cout << "5) Print out all three vectoros\n";
cout << "6) Exitting the program\n";
}
void printVector(const vector<double> &data)
{
for(int i = 0; i < data.size(); i++)
{
cout << setprecision(4) << data[i] << " ";
}
cout << "\n";
}
void pushbackVector(vector<double> &data)
{
double input;
int numOfItems;
cout << "How many items you want to add into vector?: ";
cin >> numOfItems;
for (int i = 0; i < numOfItems; i++)
{
cin >> input;
if (cin.fail())
{
cout << "Ending input.\n";
return;
}
else
{
data.push_back(input);
}
}
}
void sortVector(vector<double> &data)
{
cout << "Sorting your vector \n";
sort(data.begin(), data.end());
}

Related

Having an issue with my switch menu in a while loop

So I am working on a switch inside of a while loop. And it is not behaving properly. When I select 'l' and load the file it lets me select again, then when I try and press 'p' to print it, it just keeps looping over the selection prompt. I am pretty sure it is because choice != 'q', but don't know how to fix it.
Thank you for any help.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
//create a struct called Weather
struct Weather {
int month;
int date;
int high;
int avg;
int low;
double precip;
string event;
};
//function prototypes
int loadData(ifstream &file, Weather days[1000]);
void printData(Weather days[1000], int count);
int main() {
// declare variables
Weather days[1000];
ifstream inFile;
string checker;
char choice = '0';
int month = 0, count;
string path;
cout << "Welcome to the weather analyzer!" << endl;
while (choice != 'q') {
cout << "Would you like to (l)oad data, (p)rint data, (s)earch data, (o)rder the data, or (q)uit? ";
cin >> choice;
cout << endl;
switch (choice) {
case 'l':
// promt user for file path
cout << "Please enter the file path: ";
cin >> path;
// open the file
inFile.open(path);
// checks to see if file successfully opened and terminates if not
if (!inFile) {
cout << "Bad Path";
getchar();
getchar();
return 0;
}
loadData(inFile, days);
count = loadData(inFile, days);
break;
case 'p':
printData(days, count);
break;
case 's':
case 'o':
case 'q':
cout << "Good bye!";
break;
default:
cout << "Invalid option";
}
}
// Close file.
inFile.close();
// Pause and exit.
getchar();
getchar();
return 0;
}
//loading function
int loadData(ifstream &inFile, Weather days[1000]) {
string checker;
int month = 0;
int i; //i varaiable keeps track of how many lines there are for the print function
for (i = 0; !inFile.eof(); i++) {
inFile >> days[i].date; // gets date and checks if it is 2017 with if loop
if (days[i].date == 2017) {
getline(inFile, checker);
getline(inFile, checker);
inFile >> days[i].date; //gets correct date value
month++;//increments month counter
}
days[i].month = month;//gets and stores data from file into days
inFile >> days[i].high
>> days[i].avg
>> days[i].low
>> days[i].precip;
getline(inFile, days[i].event);
}
return i; //returns amount of days
}
// printing function
void printData(Weather days[1000], int count) {
for (int i = 0; i < count; i++) {
cout << days[i].month << " "
<< days[i].date << " "
<< days[i].high << " "
<< days[i].avg << " "
<< days[i].low << " "
<< days[i].precip << " "
<< days[i].event << " ";
cout << endl;
}
}
After reading the user input with cin, you probably want to flush the cin buffer:
cin.clear();
cin.ignore(INT_MAX);

Difficulty in a menu oriented program for C++

I am having an issue when trying to use a getline command where a user can enter in a movie and then add to the collection of movies (stored in "movies.txt")
My code is compiling, but it starts out with the 3rd case automatically. When I press "q" to quit that case, it reverts to the menu, yet when I try and write out the file or print the collection, no movie titles have been saved. Where I should go from here? I feel like I'm on the cusp of understanding this.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
const int ARRAY_SIZE = 200;
string movieTitle [ARRAY_SIZE];
int loadData (string pathname);
int writeData (string pathname);
int getTitle (string movieTitle[]);
void showAll (int count);
int main()
{
loadData("movies.txt");
char userInput;
string movieTitle[ARRAY_SIZE];
int count = getTitle(movieTitle);
bool endOfProgram = false;
while (endOfProgram ==false)
{
cout << "1. Read in Collection" << endl;
cout << "2. Print Collection" << endl;
cout << "3. Add a Movie to the Collection" << endl;
cout << "4. Write out Collection" << endl;
cout << "5. Quit the Program" <<endl;
cin >> userInput;
switch(userInput)
{
case('1'):
{
loadData("movies.txt");
break;
}
case('2'):
{
showAll(loadData("movies.txt"));
break;
}
case('3'):
{
cout << getTitle(movieTitle);
break;
}
case('4'):
{
cout <<"Write out Collection" << endl;
writeData("movies.txt");
break;
case('5'):
{
endOfProgram=true;
cout << "Have a nice day" <<endl;
break;
}
}
}
}
}
int loadData (string pathname)
{
int count = 0;
ifstream inFile;
inFile.open(pathname.c_str());
if (!inFile)
return -1;
else
{
while(!inFile.eof())
{
getline(inFile, movieTitle[count]);
count++;
}
}
return count;
}
int writeData (string pathname)
{
ofstream outfile;
outfile.open("movies.txt");
if(!outfile.is_open())
{
cout << "Cannot open movies.txt" << endl;
return -1;
}
outfile.close();
return 0;
}
void showAll (int count)
{
cout << "\n";
for (int i=0; i< count; i++)
{
cout << movieTitle[i] << endl;
}
cout << "\n";
}
int getTitle (string movieTitle[])
{
string movie;
int count = 0;
while(true)
{
cout <<"Enter Movie Titles (Type 'q' to quit)" <<endl;
cin >> movie;
if (movie == "q")
{
break;
}
movieTitle [count] = movie;
count++;
}
return count;
}
I believe cin reads until eol is found, i.e. the user presses return.
So look for integer in the userInput variable, and pass that to your switch statement
int nr = atoi(userInput.c_str())
switch(nr){
case 1:
case 2: etc ...
In your codes it is not clear why it directly goes to case '3'. It should wait for a user input first. Seems like something already available in buffer. Just put one cout statement in case '3': and check what it print. If possible put break point there and run the application in debug mode and check the value. Hope this will help you.
case('3'):
{
cout<<"Value of userInput is: "<<userInput<<endl;
cout << getTitle(movieTitle);
break;
}
Alternately you can add the below line of code just before cin like below
std::cin.clear();
cin >> userInput;
I recommend inputting an integer instead of a character for your input.
You will need to change the case values too:
int selection = 0;
//...
cin >> selection;
switch (selection)
{
case 1:
//...
}
You won't have to worry about characters in the buffer. The stream will fail if an integer is not read.

Why can't I print out my string array c++?

I have written this code and I am supposed to read in a txt file and read every other line in the txt file to the string array bookTitle[ARRAY_SIZE] and the other every other line to bookAuthor[ARRAY_SIZE]. Here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int ARRAY_SIZE = 1000;
string bookTitle [ARRAY_SIZE];
string bookAuthor [ARRAY_SIZE];
int loadData(string pathname);
void showAll(int count);
//int showBooksByAuthor (int count, string name);
//int showBooksByTitle (int count, string title);
int main ()
{
int number, numOfBooks;
char reply;
string bookTitles, authorName, backupFile;
cout << "Welcome to Brigham's library database." << endl;
cout << "Please enter the name of the backup file:";
cin >> backupFile;
numOfBooks = loadData (backupFile);
if (numOfBooks == -1) {
cout << endl;
} else {
cout << numOfBooks << " books loaded successfully." << endl;
}
cout << "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All:";
cin >> reply;
do {
switch (reply) {
case 'a':
case 'A':
cout << "Author's name: ";
cin >> authorName;
showBooksByAuthor (numOfBooks, authorName);
cout << endl;
break;
case 'q':
case 'Q':
cout << endl;
break;
case 's':
case 'S':
showAll(numOfBooks);
break;
case 't':
case 'T':
cout << "Book title: ";
cin >> bookTitles;
showBooksByTitle(numOfBooks, bookTitles);
cout << endl;
break;
default:
cout << "Invalid input" << endl;
break;
}
} while (reply != 'q' && reply != 'Q');
while (1==1) {
cin >> number;
cout << bookTitle[number] << endl;
cout << bookAuthor[number] << endl;
}
}
int loadData (string pathname){
int count = 0, noCount = -1;
ifstream inputFile;
string firstLine, secondLine;
inputFile.open(pathname.c_str());
if (!inputFile.is_open()) { //If the file does not open then print error message
cout << "Unable to open input file." << endl;
return noCount;
}
for (int i = 0; i <= ARRAY_SIZE; i++) {
while (!inputFile.eof()) {
getline(inputFile, firstLine);
bookTitle[i] = firstLine;
getline(inputFile, secondLine);
bookAuthor[i] = secondLine;
cout << bookTitle[i] << endl;
cout << bookAuthor[i] << endl;
count++;
}
}
return count;
}
void showAll (int count) {
for (int j = 0; j <= count; j++) {
cout << bookTitle[j] << endl;
cout << bookAuthor[j] << endl;
}
}
So I have the loadData function which I am pretty sure is my problem. When I have it print out each string[ith position] while running the loadData function it prints out each title and author just as it appears in the txt file. But then when I run the void showAll function which is supposed to be able to print the entire txt doc to the screen it doesn't work. Also just I checked to see if the strings were actually stored in memory and they were not. (After my do while loop I have a while loop that accepts input of type int and then prints the string array of the [input position]. This prints nothing. So what do I have to do to actually store each line to a different position in the string array(s)? Feel free to correct my code but it isn't pretty yet considering I still have two functions that I haven't done anything too. (Commented out).
You main problem is that you try to read you data using two loops rather than just one! You want read until either input fails or the array is filled, i.e., something like this:
for (int i = 0;
i < ARRAY_SIZE
&& std::getline(inputFile, bookTitle[i])
&& std::getline(inputFile, bookAuthor[i]); ++i) {
}
The problem with the original code is that it never changes the index i and always stores values into the cell with index 0. Since the input isn't checked after it is being read, the last loop iteration fails to read something and overwrites any earlier stored value with an empty value. Once reading of the stream fails the outer loop iterates over all indices but doesn't do anything as the check to the inner loop is always false.

How to alphabetize a list on C++

I have been having some trouble on my code for my final project. I have looked everwhere and I am having a hard time so I thought I would ask on here. I need to make sure that when all the names are listed in this phonebook that they will come out in alphabetical order but as of yet I am unsure how to do that. Here is the program that i currently have! Thank you!
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
struct Contact {
string name, number, notes;
};
Contact contactList[100];
int rec_num = 0;
int num_entries;
string toUpper (string S) {
for (int i= 0; i < S.length(); i++)
S[i] = toupper(S[i]);
return S;
}
void ReadFile () {
string S;
fstream input("PhoneData.txt");
while (!input.eof() && !input.fail()){
input >> contactList[rec_num].name >> contactList[rec_num].number;
getline(input, S);
contactList[rec_num].notes = S;
rec_num++;
}
cout << "Book read." << endl;
num_entries = rec_num;
input.close();
return;
}
// stores phonebook for future runs of the program
void StoreFile () {
fstream F ("PhoneData.txt");
rec_num = 0;
while (rec_num < num_entries){
F << contactList[rec_num].name << " " << contactList[rec_num].number << " " << contactList[rec_num].notes << " " << endl;
rec_num++;
}
cout << "Phonebook stored." << endl;
return;
}
// adds contact
void add_name(string name, string number, string notes){
contactList[num_entries].name = name;
contactList[num_entries].number = number;
contactList[num_entries].notes = notes;
num_entries++;
return;
}
// finds contact
void retrieve_name(string name){
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
cout << "Phone Number: " << contactList[i].number << endl << "Notes: " << contactList[i].notes << endl;
return;
}
}
cout << "Name not found" << endl;
return;
}
// updates contact info
void update_name(string name){
string new_number;
string new_notes;
cout<<"New Phone Number"<<endl;
cin>> new_number;
cout<<"New Notes"<<endl;
cin>> new_notes;
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
contactList[i].number = new_number;
contactList[i].notes = new_notes;
return;
}
}
}
// deletes contact
void delete_name(string name){
int INDEX=0;
for (int i = 0; i < num_entries; i++){
if (toUpper(contactList[i].name) == toUpper(name)) {
INDEX=i;
for ( int j=INDEX; j < num_entries; j++ ){
contactList[j].name = contactList[j+1].name;
contactList[j].number = contactList[j+1].number;
contactList[j].notes = contactList[j+1].notes;
}
}
}
return;
}
void listAllContacts() {
int i = 0;
while (i < num_entries) {
cout << "-- " << contactList[i].name << " " << contactList[i].number << endl << "-- " << contactList[i].notes << endl << endl;
i++;
}
}
int main(){
string name, number, notes;
string FileName;
char command;
FileName = "PhoneData.txt";
ReadFile ();
cout << "Use \"e\" for enter, \"f\" for find, \"l\" for list, \"d\" for delete, \"u\" for update, \"s\" for send message, \"q\" to quit." << endl << "Command: ";
cin >> command;
while (command != 'q'){
switch (command){
case 'e': cin >> name; cout << "Enter Number: ";
cin >> number; cout << "Enter Notes: ";
cin.ignore(); getline(cin, notes);
add_name(name, number, notes); break;
case 'f': cin >> name; retrieve_name(name); break;
case 'l':
listAllContacts(); break;
case 'u': cin>> name; update_name (name);break;
case 'd' : cin>> name; delete_name (name); break;
}
cout << "\nCommand: "; cin >> command;
}
StoreFile();
cout << "All set !";
return 0;
}
Given
Contact contactList[100];
int num_entries;
you can use std::sort to sort the list of contacts. std::sort has two forms. In the first form, you can use:
std::sort(contanctList, contactList+num_entries);
if you define operator< for Contact objects.
In the second form, you can use:
std::sort(contanctList, contactList+num_entries, myCompare);
if you define myCompare to be callable object that can compare two Contact objects.
To use the first form, change Contact to:
struct Contact {
string name, number, notes;
bool operator<(Contact const& rhs) const
{
return (this->name < rhs.name);
}
};
If you want to the comparison of names to be case insensitive, convert both names to either uppercase or lowercase and them compare them.

String Vector program exits before input

So, I have a project that must add, delete, and print the contents of a vector... the problem is that, when run the program exits before I can type in the string to add to the vector. I commented the function that that portion is in.
Thanks!
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
using namespace std;
void menu();
void addvector(vector<string>& vec);
void subvector(vector<string>& vec);
void vectorsize(const vector<string>& vec);
void printvec(const vector<string>& vec);
void printvec_bw(const vector<string>& vec);
int main()
{
vector<string> svector;
menu();
return 0;
}
//functions definitions
void menu()
{
vector<string> svector;
int choice = 0;
cout << "Thanks for using this program! \n"
<< "Enter 1 to add a string to the vector \n"
<< "Enter 2 to remove the last string from the vector \n"
<< "Enter 3 to print the vector size \n"
<< "Enter 4 to print the contents of the vector \n"
<< "Enter 5 ----------------------------------- backwards \n"
<< "Enter 6 to end the program \n";
cin >> choice;
switch(choice)
{
case 1:
addvector(svector);
break;
case 2:
subvector(svector);
break;
case 3:
vectorsize(svector);
break;
case 4:
printvec(svector);
break;
case 5:
printvec_bw(svector);
break;
case 6:
exit(1);
default:
cout << "not a valid choice \n";
// menu is structured so that all other functions are called from it.
}
}
void addvector(vector<string>& vec)
{
string line;
int i = 0;
cout << "Enter the string please \n";
getline(cin, line); // doesn't prompt for input!
vec.push_back(line);
}
void subvector(vector<string>& vec)
{
vec.pop_back();
return;
}
void vectorsize(const vector<string>& vec)
{
if (vec.empty())
{
cout << "vector is empty";
}
else
{
cout << vec.size() << endl;
}
return;
}
void printvec(const vector<string>& vec)
{
for(int i = 0; i < vec.size(); i++)
{
cout << vec[i] << endl;
}
return;
}
void printvec_bw(const vector<string>& vec)
{
for(int i = vec.size(); i > 0; i--)
{
cout << vec[i] << endl;
}
return;
}
When running the program, you typed the number 1 to tell your program that you want to add. After you typed 1, you hit Enter, which puts a newline in the input waiting to be read. In the addvector function, readline reads that newline.
Since this is homework, it's better if you figure out the solution yourself, now that you understand the problem.
The >> and getline calls aren't being nice to each other. The '>>' doesn't swallow the \n, which ends up yielding an empty string in getline.