Program is skipping over Getline() without taking user input [duplicate] - c++

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 9 years ago.
This is a very strange problem, when my program asks the user for the address, instead of waiting for input, it seems to skip the getline() function completely
Answerinput:
cout << "would you like to add another entry to the archive? (Y/N):";
cin >> answer;
cout << endl;
cout << endl;
answer = toupper(answer);
switch(answer)
{
case 'Y':
Entrynumber++;
cout << "began record number " << Entrynumber << "+ 1." << endl;
cout << "Enter the last name of the person to be entered" << endl;
cin >> stringentry;
cout << endl;
stringlength = stringentry.length();
strcpy(Record[Entrynumber].Last_Name, stringentry.c_str());
Record[Entrynumber].Last_Name[stringlength] = '*';
cout << "Enter the first name of the person" << endl;
cin >> stringentry;
cout << endl;
stringlength = stringentry.length();
strcpy(Record[Entrynumber].First_Name, stringentry.c_str());
Record[Entrynumber].First_Name[stringlength] = '*';
cout << "Enter the SSN of the person" << endl;
cin >> Record[Entrynumber].SSN;
cout << endl;
cout << "Enter the age of the person" << endl;
cin >> Record[Entrynumber].Age;
cout << endl;
cout << "Enter the address of the person" << endl;
cin.getline(Record[Entrynumber].Address,70);
cout << endl;
stringentry = Record[Entrynumber].Address;
stringlength = stringentry.length();
Record[Entrynumber].Address[stringlength] = '*';
cout << "you entered:" << endl;
for(jim = 0 ; Record[Entrynumber].Last_Name[jim + 1] != '*' ; jim++)
{
cout << Record[Entrynumber].Last_Name[jim];
}
cout << ',' ;
for(jim = 0 ; Record[Entrynumber].First_Name[jim + 1] != '*' ; jim++)
{
cout << Record[Entrynumber].First_Name[jim];
}
cout << endl;
cout << Record[Entrynumber].SSN << endl;
cout << Record[Entrynumber].Age << endl;
for(jim = 0 ; Record[Entrynumber].Address[jim + 1] != '*' ; jim++)
{
cout << Record[Entrynumber].Address[jim];
}
cout << endl;
cout << endl;
goto Answerinput;
case 'N':
cout << "ok" << endl;
break;
default:
cout << "invalid answer" << endl;
goto Answerinput;
}
output to console
would you like to add another entry to
the archive? (Y/N):Y
began record number 6+ 1.
Enter the last name of the person to be entered
John
Enter the first name of the person
John
Enter the SSN of the person 22222222
Enter the age of the person 22
Enter the address of the person
you entered:
Joh,Joh
22222222
22
*¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
//////////////22 more lines of'|'//////////////////////////////////////////////
...
¦¦¦¦¦¦¦¦l3-j
would you like to add another entry to the archive? (Y/N):
Both cin.getline() and getline() do the same thing.
I'm using MVC++ 2008.
All of the fields in the Record array are structs, Record[Entrynumber].Address is a char array.

Cin is probably leaving the carriage return in the buffer which getline retrieves. Try
cin.ignore(1000, '\n');
cin.getline(Record[Entrynumber].Address,70);
The >> operator doesn't remove the newline character after retrieving data, but ignores leading whitespace before retrieving data, while getline just retrieves whatever is in there, and removes the '\n' after reading as it is apart of the line it is 'getting'.

Seeing as how there might be input left over in the buffer which your getline is reading first, I'd suggest you clear the buffer before trying to input the next data:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');

Related

Use of getline to read a string with white spaces in a structure

I want to read strings with white spaces into members of a structure. Tried using getline but both the output statements are clubbed with a single cin for both. As per the similar posts here, tried using cin.ignore, but the input is not read into the member of the structure. Pls help. It's a part of my assignment and I'm a beginner in C++. This is how my code looks like:
#include <string.h>
using namespace std;
struct book {
string title, author;
int no_of_pages, year;
float price;
};
int main() {
int N;
cout << "Enter the no. of books whose details are to be entered:" << endl;
cin >> N;
book b[N];
int x;
for (x = 0; x < N; x++) {
cout << "Enter the title of book #" << x + 1 << ":" << endl;
getline(cin, (b[x].title));
// cin.ignore();
cin.ignore(1000, '\n');
cout << "Enter the author's name:" << endl;
getline(cin, (b[x].author));
cout << "Enter the no. of pages:" << endl;
cin >> b[x].no_of_pages;
cout << "Enter the price of book:" << endl;
cin >> b[x].price;
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
}
for (x = 0; x < N; x++) {
cout << "\n\n";
cout << "The details of book" << x + 1 << " are:" << endl;
cout << "Title :" << b[x].title << endl;
cout << "Author :" << b[x].author << endl;
cout << "No. of pages :" << b[x].no_of_pages << endl;
cout << "Price :" << b[x].price << endl;
cout << "Publishing year:" << b[x].year << endl;
cout << "---------------------------------------------";
}
return 0;
}
There's no point in using cin.ignore() in between two calls to getline. ignore is used to discard remaining characters after numeric input. So the place to use it is after numeric input and before the next getline. Like this
cout << "Enter the title of book #" << x + 1 << ":" << endl;
getline(cin, (b[x].title));
cout << "Enter the author's name:" << endl;
getline(cin, (b[x].author));
cout << "Enter the no. of pages:" << endl;
cin >> b[x].no_of_pages;
cout << "Enter the price of book:" << endl;
cin >> b[x].price;
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
cin.ignore(1000, '\n');
That said I would just read everything using getline, then convert the strings to numbers where needed. That's simpler and cleaner, all you need to know is how to convert a string to an integer, which you can easily research for yourself.
There are two places you should put cin.ignore in your code:
cout << "Enter the no. of books whose details are to be entered:" << endl;
cin >> N;
// First cin.ignore here
cin.ignore(1000, '\n');
cout << "Enter the year of publishing" << endl;
cin >> b[x].year;
// Second cin.ignore here
cin.ignore(1000, '\n');
Besides this I see two more problems in your code:
#include <string> not <string.h>
add #include <iostream>
Why cin.ignore is necessary? User is expected to provide new line ('\n') delimited input. When getline is used, it leaves the input stream in such a state that the next attempt to read input from stream will start at next line. This is not true for operator >>. What int x; cin >> x; does here is it reads only the integer not the new line character present right after the integer. Hence, the next attempt to read will continue within the same line. getline will then find no character before new line and hence will fetch an empty string. To avoid this and to effectively start reading from the next line, cin.ignore is necessary.

Verifying User Input as Integer: User has to enter input twice

I am prompting the user to enter an integer value. When the value is incorrect, the program works. However, when the user enters an integer input, the user needs to enter the input twice.
I looked at other tutorials on how to use the while loop to catch erroneous input, and that part worked for me. However, the integer values need to be entered twice in order for the program to run.
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
cin >> input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}
You ask for the input twice:
cin >> input;
while(!(cin >> input )){
Removing the first line might make it work you intended.
'The user has to enter the input twice' Look at your code
int input;
cin >> input;
while(!(cin >> input )){
How many times do you ask the user for input?
You'd have more luck with this
int input;
while(!(cin >> input )){
Your error recovery code looks reasonable, haven't tested it though.
int input;
while (cout << "Your choice: ",
!(cin >> input) || input < 1 || 9 < input)
{
cin.clear();
while (cin.get() != '\n');
cerr << "Invalid input! Please try again!\n";
}
Thanks everyone! The "cin >> input;" line was unnecessary. At first, I left it there because it would actually tell the user the error message if the user entered a numeric input such as a double. So, if the user entered something like 3.3, the program would display an error message that I specified ("Please enter an integer" line). However, the program in this case (when there is a double) asks the user to prompt for the integer input twice and then continues the program. When I delete the said unnecessary line, the program accepts a double input, but what it does, it takes the numeric value before the decimal point and uses it as the integer. So, a value of 1.2 is recorded as 1 when I tested it. I'm unsure why this phenomenon happens, but the program works otherwise. Maybe it accounts for human error?
#include <iostream>
using namespace std;
int main() {
cout << "*************************************************" << endl;
cout << "******************|DVD Library|******************" << endl;
cout << "*************************************************" << endl;
cout << "1.\tAdd DVD" << endl;
cout << "2.\tDelete DVD" << endl;
cout << "3.\tSearch DVD" << endl;
cout << "4.\tList All DVDs in the Library" << endl;
cout << "5.\tAdd DVD to Favorites List" << endl;
cout << "6.\tDelete DVD from Favorites List" << endl;
cout << "7.\tSearch DVD in Favorites List" << endl;
cout << "8.\tList All DVDs in Favorites List" << endl;
cout << "9.\tQuit" << endl;
cout << "*************************************************" << endl;
int input;
while (!(cin >> input)) {
cin.clear();
while (cin.get() != '\n')
continue;
cout << "Please enter an integer --> " << flush;
}
if (input < 1 || input > 9) {
cout << "Invalid input! Please try again!" << endl;
}
return 0;
}

How to list how many iterations of a struct are stored inside a vector?

I'm new to c++ (and coding in general) and have recently been working with a struct held inside a vector, in this case :
struct Contact{
string name;
string address;
string phone;
string email;};
vector<Contact> contacts;
So, one of my functions involves searching through each of the contacts to find the one for which the string stored in name matches a search input. To do this I made a for loop as such:
for(int i = 0; i < contacts.size(); i++){
if(contacts[i].name == searchInput){
cout << contacts[i].address << "\n\r" << contacts[i].phone << "\n\r" << contacts[i].email;
But for some reason this was only able to find the correct contact if it was the name stored at:
contacts[0].name
and none of the others. So while trying to figure out what was wrong, I decided to do
cout << contacts.size();
which I thought should output 3, because I have only three contacts stored. Yet for some reason, it output 7. Is there anyway for me to accurately list the number of iterations of Contact stored in the contacts vector in order to get my for loop to work?
Edit for my full code:
#include <vector>
#include <iostream>
#include <fstream>
using namespace std;
struct Contact
{
string name;
string address;
string phone;
string email;
};
bool go;
bool a = false;
char command;
string endL = "\n\r";
string tab = "\t";
string line;
int i;
int counter = 0;
int contactCounter = 0;
vector<Contact> contacts;
void add(){
contacts.push_back(Contact());
int newcontact = contacts.size() - 1;
string input;
cout << "Enter the name: " << endL;
cin >> input;
contacts[newcontact].name = input;
cout << "Enter the address: " << endL;
cin >> input;
contacts[newcontact].address = input;
cout << "Enter the phone number: " << endL;
cin >> input;
contacts[newcontact].phone = input;
cout << "Enter the email address: " << endL;
cin >> input;
contacts[newcontact].email = input;
}
void search(string name){
for(int i = 0; i < contacts.size(); i++){
if(contacts[i].name == name){
cout << "Name: " << contacts[i].name << endL << "Address: " << contacts[i].address << endL << "Phone Number: " << contacts[i].phone << endL << "Email: " << contacts[i].email << endL << endL;
a = true;
}
}
if(a == false){
cout << "There is no contact under that name." << endL;
}
}
int main() {
ifstream phonebook;
phonebook.open("phonebook.txt");
if(phonebook.is_open()){
while(getline(phonebook,line)){
if(line.empty() == false){
if(counter % 4 == 0){
contacts.push_back(Contact());
contacts[contactCounter].name = line;
}else if(counter % 4 == 1){
contacts[contactCounter].address = line;
}else if(counter % 4 == 2){
contacts[contactCounter].phone = line;
}else if(counter % 4 == 3){
contacts[contactCounter].email = line;
contactCounter++;
}
counter++;
}
}
}else{cout << "an error has occurred while opening the phonebook";}
phonebook.close();
cout << contacts.size() << endL;
cout << "Enter a command." << endL << tab << "To add a contact, enter '+'" << endL << tab << "To search for a contact, enter 's'" << endL << tab << "To delete a contact, enter '-'" << endL << tab << "To quit the program, enter 'q'" << endL;
cin >> command;
while(command != 'q'){
if(command == '+'){
add();
command = '/';
}
else if(command == 's'){
string searched;
cout << "Please enter who you would like to search for: ";
cin >> searched;
search(searched);
command = '/';
}
else if(command == '-'){
cout << "Not done." << endL;
command = '/';
}
else if(command == '/'){
cout << "Enter a command." << endL << tab << "To add a contact, enter '+'" << endL << tab << "To search for a contact, enter 's'" << endL << tab << "To delete a contact, enter '-'" << endL << tab << "To quit the program, enter 'q'" << endL;
cin >> command;
}
else{
cout << "That command is invalid." << endL;
cout << "Enter a command." << endL << tab << "To add a contact, enter '+'" << endL << tab << "To search for a contact, enter 's'" << endL << tab << "To delete a contact, enter '-'" << endL << tab << "To quit the program, enter 'q'" << endL;
cin >> command;
}
}
ofstream newbook;
newbook.open("phonebook.txt");
if(newbook.is_open()){
for(int i=0; i < contacts.size(); i++){
newbook << contacts[i].name << endl;
newbook << contacts[i].address << endl;
newbook << contacts[i].phone << endl;
newbook << contacts[i].email << endl;
newbook << endL;
}
}else{cout << "there was an issue saving your contacts" << endL;}
newbook.close();
return 0;
}
There's actually nothing wrong with your code except this line
string endL = "\n\r";
Which should really only be
string endL = "\n";
\n is automatically converted to the line endings used by the system, which traditionally is \n (0x0a) on unix systems and \r\n (0x0d0a) on Windows.
But, how did this affect the program so much? Well it only takes affect after the phonebook is written at the end of the program so that phonebook.txt contains these bogus line endings that have \r\n\r at the end (on Windows). So when the file is read, it reads up until the new line \r\n and sees \rPerson Name as line after! Which explains why searching was failing.
You also may see some additional bogus contacts generated because there may be some extra \rs at the end which read as a single line each. Without looking at your phonebook.txt I can't say for certain why you have an additional 4 though I'd guess extra \rs would be the cause.
All in all, use \n for new lines.
To answer the title, vector::size() is THE way to get the number of stored objects in a vector. It's not lying to you.
Using the range based for loop ensures that you won't hit any nonexistent contacts:
for(auto&& contact: contacts)
{
// Contact contact is now accessible.
}
Also, it is probably not a good idea to store a as a global variable. What happens if you execute search twice?

C++ user input closes program debug

I got a C++ program that waits for user input and only closes if the user inputs 'q', and will loop back to the menu if anything else is entered.
At least that's what it's supposed to do. Instead of looping back, the program closes anyway.
int main()
{
Hierarchy roster;
char input=' ';
bool done = false;
string first, last, full, boss, title;
while (done != true){
cout << "Organizational Chart builder, version 0.1" << endl;
cout << "Please choose your next command: /n";
cout << " q to quit the program " << endl;
cout << " a to add a person " << endl;
cout << " c to count the number of people under someone" << endl;
cout << " p to print the hierarchy " << endl;
cout << " r to remove someone from the hierarchy " << endl;
cin >> input;
switch(input)
{
case 'q':
done = true;
break;
case 'a':
cout << "Please enter the person't first name: ";
cin >> first;
cout << "Please enter the person's last name: ";
cin >> last;
cout << "Please enter the person's title";
cin >> title;
cout << "Please enter " + first + last +"'s boss. Please enter the full name and title. If there is none, type none:";
cin >> boss;
if (boss == "none")
roster.insert(full);
else
roster.contains(boss);
roster.insert(full);
break;
case'c':
cout << "Enter the first name of the person you are searching for: ";
cin >> first;
cout << "Enter the last name: ";
cin >> last;
cout << "What is the person's title:";
cin >> title;
full = first + " " + last + " " + title;
roster.contains(full);
roster.countb(full);
break;
case 'p':
roster.print();
break;
case 'r':
cout << "Please enter the first, last, and title of the person you want removed: ";
cin >> full;
roster.removeNode(full);
break;
}
}
cout << "Program closed. " << endl;
return 0;
}
EDIT: Got it working now. Thanks
Your return statement is in your while loop. Take it out and you should be okay.
ie. return 0;}} -> } return 0;}

How can I avoid bad input from a user?

I am a very newbie programmer, so I don't really know much about writing code to protect the application.. Basically, I created a basicMath.h file and created a do while loop to make a very basic console calculator (only two floats are passed through the functions). I use a series of if and else if statements to determine what the users wants to do. (1.add, 2.subtract, 3.multiply, 4.divide) I used a else { cout << "invalid input" << endl;} to protect against any other values, but then I tried to actually write a letter, and the program entered a infinite loop. Is there anyway to protect against users who accidentally hit a character instead of a number?
`#include <iostream>
#include "basicMath.h"
using namespace std;
char tryAgain = 'y';
float numOne = 0, numTwo = 0;
int options = 0;
int main()
{
cout << "welcome to my calculator program." << endl;
cout << "This will be a basic calculator." << endl;
do{
cout << "What would you like to do?" << endl;
cout << "1. Addition." << endl;
cout << "2. Subtraction." << endl;
cout << "3. Multiplication" << endl;
cout << "4. Division." << endl;
cin >> options;
if (options == 1){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " + " << numTwo << " = " << add(numOne, numTwo) << endl;
}
else if (options == 2){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " - " << numTwo << " = " << subtract(numOne, numTwo) << endl;
}
else if (options == 3){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " * " << numTwo << " = " << multiply(numOne, numTwo) << endl;
}
else if (options == 4){
cout << "Enter your first number." << endl;
cin >> numOne;
cout << "Enter your second number." << endl;
cin >> numTwo;
cout << numOne << " / " << numTwo << " = " << divide(numOne, numTwo) << endl;
}
else {
cout << "Error, invalid option input." << endl;
}
cout << "Would you like to use this calculator again? (y/n)" << endl;
cin >> tryAgain;
}while (tryAgain == 'y');
cout << "Thank you for using my basic calculator!" << endl;
return 0;
}
`
One way would be to use exception handling, but as a newbie you're probably far from learning that.
Instead use the cin.fail() which returns 1 after a bad or unexpected input. Note that you need to clear the "bad" status using cin.clear().
A simple way would be to implement a function:
int GetNumber ()
{
int n;
cin >> n;
while (cin.fail())
{
cin.clear();
cin.ignore();
cout << "Not a valid number. Please reenter: ";
cin >> n;
}
return n;
}
Now in your main function wherever you are taking input, just call GetNumber and store the returned value in your variable. For example, instead of cin >> numOne;, do numOne = GetNumber();
When you input to cin, it is expecting a specific type, such as an integer. If it receives something that it does not expect, such as a letter, it sets a bad flag.
You can usually catch that by looking for fail, and if you find it, flush your input as well as the bad bit (using clear), and try again.
Read a whole line of text first, then convert the line of text to a number and handle any errors in the string-to-number conversion.
Reading a whole line of text from std::cin is done with the std::getline function (not to be confused with the stream's member function):
std::string line;
std::getline(std::cin, line);
if (!std::cin) {
// some catastrophic failure
}
String-to-number conversion is done with std::istringstream (pre-C++11) or with std::stoi (C++11). Here is the pre-C++11 version:
std::istringstream is(line);
int number = 0;
is >> number;
if (!is) {
// line is not a number, e.g. "abc" or "abc123", or the number is too big
// to fit in an int, e.g. "11111111111111111111111111111111111"
} else if (!is.eof()) {
// line is a number, but ends with a non-number, e.g. "123abc",
// whether that's an error depends on your requirements
} else {
// number is OK
}
And here the C++11 version:
try {
std::cout << std::stoi(line) << "\n";
} catch (std::exception const &exc) {
// line is not a number, e.g. "abc" or "abc123", or the number is too big
// to fit in an int, e.g. "11111111111111111111111111111111111"
std::cout << exc.what() << "\n";
}