String Vector program exits before input - c++

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.

Related

Dealing with file io in c++

I have a program that takes input for names and outputs the last names in a string. The task I have now is to include FileIO in it. Specifically, "get user input for the filename, and then read the names from the file and form the last name string."
When I run the program, the console will show the name string from the text file. But only initially. As you keep entering names, that string disappears. Also, my user input for file name seems to be doing nothing, because I can enter anything and it still show the string of last names from the text file.
Here is what I have so far. Included all of it, just to make sure.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
using namespace std;
// function declerations
int Menu();
void getName(vector<string> &names, int &count);
void displayName(vector<string> &names, int count);
string getLastNames(vector<string> &names, int count);
int main()
{
vector<string> names;
int count = 0;
int choice = Menu();
ifstream File;
string line;
cout << "Enter file name: ";
getline(cin,line);
File.open("File.txt");
while(File.good()){
getline(File,line);
cout << line << endl;
}
File.close();
while (choice != 0)
{
// switch statement to call functions based on users input
switch (choice)
{
case 1: {
getName(names, count);
} break;
case 2: { displayName(names, count); } break;
case 3: {
cout << getLastNames(names, count) << endl;
} break;
case 0: {
return 0;
} break;
}
choice = Menu();
}
return 0;
}
// function definition for vector of strings
void getName(vector<string> &names, int &count)
{
string name;
// get input for name
cout << "Enter name: ";
getline(cin, name);
// find position of space in string
int pos = name.find(' ');
// reverse order of name
if(pos != -1) {
string first = name.substr(0, pos);
string last = name.substr(pos+1);
name = last + "," + first;
}
// add name to end of vector
names.push_back(name);
count++;
}
// give user option of what to do
int Menu() {
int choice;
cout << "1. Add a name" << endl;
cout << "2. Display names " << endl;
cout << "3. Show all Last Names" << endl;
cout << "0. Quit" << endl;
cout << "Enter a option: ";
cin >> choice;
// if outside of above choices, print 'choice not on list'
while (choice < 0 || choice > 3)
{
cout << "Choice not on list: ";
cin >> choice;
}
cin.ignore();
return choice;
}
// defining function that gets last names
string getLastNames(vector<string> &names, int count) {
stringstream ss;
for (int i = 0; i<count; i++)
{
int pos = names[i].find(',');
if (pos != -1) {
ss << "\"" << names[i].substr(0, pos) << "\", ";
} else {
ss << "\"" << names[i] << "\", ";
}
}
return ss.str();
}
// display the names
void displayName(vector<string> &names, int count)
{
if (count == 0)
{
cout << "No names to display" << endl;
return;
}
for (int i = 0; i<count; i++)
{
cout << names[i] << endl;
}
}

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.

Blank string input first time through loop? (c++) [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 6 years ago.
I'm trying to get user input of names to store in a vector.
Every time I run through the for loop, it always takes blank input in the temp string variable the first time through the loop.
What I get when I run this program is something like:
,
Dylan, Bob
Brown, Mark
Rogers, Mr
Thanks for any help
Sorry first post =P
Heres the code:
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
void getNames(vector<string> &n, int&);
void displayNames(vector<string> &n, int&);
void saveNames(vector<string> &n, int&);
void readNames(vector<string> &n, int&);
void sortNames(vector<string> &n, int&);
int main(){
vector<string> names;
int b = 0;
int choice;
while(choice != 5){
cout << "1 - Enter a Character" << endl;
cout << "2 - Display List of Characters" << endl;
cout << "3 - Save List of Characters to File" << endl;
cout << "4 - Read List of Characters from File" << endl;
cout << "5 - Exit the program" << endl << endl;
cin >> choice;
switch(choice){
case 1: getNames(names, b); break;
case 2: displayNames(names, b); break;
case 3: saveNames(names, b); break;
case 4: readNames(names, b); break;
}
}
return 0;
}
void getNames(vector<string> &n, int &b){
string temp;
cout << "Enter Names. Press \'quit\' to stop." << endl;
for(b; temp != "quit"; b++){
getline(cin, temp);
if(temp == "quit"){
break;
}else{
int space = temp.find(' ', 0);
string inPut = temp.substr((space+1), temp.length());
inPut += ", ";
inPut += temp.substr(0, space);
n.push_back(inPut);
}
}
}
void displayNames(vector<string> &n, int &b){
for(int c=0; c < b; c++){
cout << n[c] << endl;
}
}
void saveNames(vector<string> &n, int &b){
ofstream outFile;
outFile.open("names.txt", ios::app);
if(!outFile.fail()){
for(int i=0; i < b; i++){
outFile << n[i] << endl;
}
cout << "Names written to File" << endl;
}else{
cout << "ERROR: File could not be opened" << endl;
}
outFile.close();
}
void readNames(vector<string> &n, int&){
string line;
ifstream inFile("names.txt");
if(inFile.is_open()){
while(getline(inFile, line)){
cout << line << endl;
}
inFile.close();
}else{
cout << "Cannot open File" << endl;
}
}
void sortNames(vector<string> &n, int&){
//for(int i=0; i < b; i++){}
}
By fixing your curly braces your getNames() function works for me as expected. Maybe this is an oversight from posting your code, but you are missing a curly brace to end your for loop and function call for GetNames(). Compiling and using this code produces the expected output:
void getNames(vector<string> &n, int &b){
string temp;
cout << "Enter Names. Press \'quit\' to stop." << endl;
for(b; temp != "quit"; b++){
getline(cin, temp);
if(temp == "quit"){
break;
}else{
int space = temp.find(' ', 0);
string inPut = temp.substr((space+1), temp.length());
inPut += ", ";
inPut += temp.substr(0, space);
cout << inPut << endl; //Testing string transformation before insertion.
n.push_back(inPut);
}
}
}
Passing the names: "Bob Dylan", "Jerry McQuire", and "Some Guy" resulted in the output
Dylan, Bob
McQuire, Jerry
Guy, Some
It is possible that there is an error somewhere else in the code if your first element in the Vector is always blank. The error is possibly in the saveNames() or readNames() functions. But the strings are input and transformed correctly here. It's beneficial to post all the code relevant to your question ahead of time.
Please include this at the top of getNames():
cin.clear();
cin.ignore(10000, '\n');
This will clear the cin buffer to a new line so the initial choice from main() doesn't get put in to the vector unexpectedly.
Why are you using a for loop? is better to use a while loop like so:
void getNames(vector<string> &n, int &b)
{
string temp;
cout << "Enter Names. Press \'quit\' to stop." << endl;
getline(cin, temp);
while(temp != "quit")
{
int space = temp.find(' ', 0);
string inPut = temp.substr((space+1), temp.length());
inPut += ", ";
inPut += temp.substr(0, space);
n.push_back(inPut);
getline(cin, temp);
}
...//the rest of your code...
}
I didn't answer the question, sorry... the first input is the termination character of your last cin... std::getline (string)

Infinite loop reading from stdin using cin::fail()

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());
}

Bank System not working

For some reason my bank script isn't working. More specifically, the search() does not work. I kind of understand why it doesn't, probably because of if(obj.returnId() == n), but I have no clue how to fix it. When I search an account, it will only allow me to find the last account made, not any of the previous ones. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <string.h>
#include <fstream>
#include <Windows.h>
#include <conio.h>
using namespace std;
bool loop = true;
class account
{
int id;
char name[40];
char password[40];
public:
void getData()
{
cout << "\nEnter your name: ";
cin >> name;
cout << "\nEnter ID: ";
cin >> id;
cout << "\Enter pass: ";
cin >> password;
}
void showData()
{
cout << "\nName: ";
puts(name);
cout << "\nID: " << id;
cout << "\n";
}
int returnId()
{
return id;
}
};
void createAccount()
{
account obj;
ofstream fileCreate;
fileCreate.open("accounts.dat", ios::binary|ios::app);
obj.getData();
fileCreate.write((char*)&obj,sizeof(obj));
fileCreate.close();
}
void display()
{
account obj;
ifstream fileRead;
fileRead.open("accounts.dat", ios::binary);
while(fileRead.read((char*)&obj, sizeof(obj)))
{
obj.showData();
}
fileRead.close();
}
void search(int n)
{
account obj;
ifstream fileRead;
fileRead.open("accounts.dat", ios::binary);
while(fileRead.read((char *) &obj, sizeof(obj)) );
{
fileRead.seekg(0,ios::beg);
if(obj.returnId() == n)
{
obj.showData();
}
else {
cout << "\nUser not foud!\n";
}
}
fileRead.close();
}
void main()
{
cout << "Welcome to the Bank.\n\n";
while (loop==true)
{
char choice[10];
cout << "Please select an option:\n";
cout << "------------------------------------------------\n";
cout << "(a)Log into an account\n(b)Create an account\n(s)Search an account\n(e)Exit\n";
cout << "------------------------------------------------\n";
cout << "Choice: ";
cin >> choice;
choice[0] = tolower(choice[0]);
cout << "\n------------------------------------------------\n\n";
switch (choice[0])
{
case 'a':
display();
break;
case 's':
int n;
cout << "Enter the ID of the account: ";
cin >> n;
search(n);
break;
case 'b':
createAccount();
break;
case 'e':
loop = false;
break;
default:
system("CLS");
cout << "The option \"" << choice[0] << "\" is invalid.\n\n\n\n";
break;
}
};
cout << "\n\n\n";
cout << "Click anything to exit.";
getch();
}
Your problem is the semicolon at the end of this line:
while(fileRead.read((char *) &obj, sizeof(obj)) );
That makes this loop have an empty body. So you basically read the whole file and throw away the results, except for the last entry.
get rid of this also:
fileRead.seekg(0,ios::beg);
I don't know why you need that, it would only make you read the first entry over and over.
The other error is that you should only say 'User not found' when you've tested all the accounts and they all failed. Your loop (when you've removed the semi-colon) is saying 'User not found' after every failed test.
You probably don't find the entry you are looking for because each time you have read an entry from the file, you reset the position to the beginning. This means that your loop will run forever, reading the same entry over and over again and never finding the entry you search for.
the seek might be the problem:
while(fileRead.read((char *) &obj, sizeof(obj)) ) //;
{
// seek to start?
//fileRead.seekg(0,ios::beg);
...
}
have a look at http://www.boost.org/doc/libs/1_51_0/libs/serialization/doc/index.html
aside, use
cout << "text" << endl;
for platform-agnostic newlines.