Unexpected infinite loop (C++) - c++

while(true)
{
unsigned int option;
cout<<"1 - Display the list\n";
cout<<"2 - Add a game title to the list\n";
cout<<"3 - Remove a game title from the list\n";
cout<<"4 - Exit\n";
cin>>option;
if(option == 1)
{
if(gameTitles.empty())
{
cout<<"\nThere are no games to be displayed. Please try again after adding some games to the list.\n";
}
else
{
for(iter = gameTitles.begin(); iter != gameTitles.end(); ++iter)
{
cout<<*iter<<endl;
}
}
}
else if(option == 2)
{
cout<<"\nEnter the game's title:\n";
cin>>newGame;
gameTitles.push_back("newGame");
}
else if(option == 3)
{
cout<<"\nEnter a game to be removed:\n";
cin>>removeGame;
theIterator = find(gameTitles.begin(),gameTitles.end(),removeGame);
theIterator = gameTitles.erase(theIterator);
}
else if(option == 4)
{
break;
}
else
{
cout<<"\nThe option is illegal. Please try again.\n";
}
}
When I choose any 1, 3, 4 or illegal option, the loop brings me to the top and I have possibility to choose again. The problem arises when I am trying to use 2nd option. I just enter in an infinite loop. But I want to enter a game title and after it is added to my vector (I declared it earlier) and then have possibility to choose an option again.

You don't show the type of newGame but I would guess that it is of type std::string and you enter a title with two words: the stream reads the first word and stops reading. The next thing you do is read an int which fails and leaves the value of option unchanged. From then on the stream won't do anything and just keeps reading.
The key error is not checking that the read attempt was successful before using the result: you always need to verify that your input was successful after reading and before using the result. When an input operation fails the stream goes into failure mode, i.e., std::ios_base::failbit gets set, and it converts to false instead of true (well, actually it converts to a null pointer vs. a non-null pointer but that's a detail irrelevant to this discussion). Once in failure state the stream won't do anything until the stream state is clear()ed. You you probably also need to ignore() the offending characters.
That is, you certainly should use something like
if (std::cin >> option) {
// do something with the option
}
else {
std::cout << "expected an integer: ignoring the line\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
To read the title you should probably read an entire line. Since the formatted input for the option will leave the newline character in the stream, you will first need to skip that character, though. That is, the input for the new title would look something like this:
if (std::getline(std::cin >> std::ws, newGame)) {
// ...
}
The std::ws manipulator skips all leading whitespace. That is probably OK for your needs. If the string being read can have leading whitespace characters something different will be needed.

Before you try to cin again to the same variable newgame, put in a cin.ignore(). If I recall correctly, the first time you cin to a string (I'm assuming newgame is a string), it leaves a trailing \n so it will just automatically enter through in later prompts.

Related

Pause Function it is Looping Forever

I am trying to implement a pause function in C++, but it is looping forever.
I am using macOS but I am trying to create a pause function that will work in any system... I believe my cin >> is not capturing '\n' or '\r' from the keyboard and it is looping forever.
void Transferencia::pause() {
char enter = 0;
while(enter != '\n' && enter != '\r') {
cout << "(Press Enter to Continue...) ";
cin >> enter;
}
cin.clear();
}
I want to pause my program until user press the key "enter".
But even when I press "enter/return" it keeps looping...
At very first: enter != '\n' || enter != '\r' is a tautology: Even if enter does equal one of the characters it cannot be equal to the other one. So one of the tests must be true... You actually want to stay in the loop when enter is unequal to both values.
std::cin >> ... won't read data before you press enter, but it will discard the newlines (actually, all whitespace). So it would suffice just to read one single character right without loop (the loop again would get an endless one); solely: If the user doesn't enter anything at all before pressing 'enter' key, there's no character to read from std::cin and we'd still be waiting.
What you can do is reading entire lines:
std::string s;
std::getline(std::cin, s);
That will accept empty lines as well, so does exactly what you want (note: no loop around!).
Edit (stolen from the comments; thanks, Thomas Matthews): An even more elegant way is
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
as it won't create any additional resources that would be discarded afterwards anyway (the std::string object!).
Edit 2:
Depending on type of last input operation, there might still be a newline (or even further data) buffered, e. g. after int n; std::cin >> n;. In this case, you need to skip the input yet buffered. So you would need ignore twice.
However, if the last input operation consumed the newline already (e. g. std::getline – or if there wasn't any preceding input operation at all), then this would lead to user having to press enter twice. So you need to detect what's has been going on before.
std::cin.rdbuf().in_avail() allows you to detect how many characters are yet buffered. So you can have:
if(std::cin.rdbuf().in_avail())
{
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
std::cout << "press enter" << std::endl;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
On some systems (including mine), though, in_avail can return 0 even though a newline is yet buffered! std::cin.sync_with_stdio(false); can fix the issue; you should execute it before very first input operation. Hopefully, you don't use C++ (streams) and C (scanf, printf, etc) IO intermixed then...
The easiest way to do this is with getline().
cin >> ignores whitespace, newline characters included. getline() will read an entire line, newline character included. However, it does not copy the newline character to the output string. If the user simply hit the enter key and nothing else, you'd end up with an empty string.
So, to get your desired behavior, you would construct your loop like this:
string line;
while(true)
{
cout << "(Press Enter to Continue...) " << endl;
getline(cin, line);
if(line == "")
break;
}
#Aconcagua has answered your question but this is what I want to add in.
Normally, for handling some specific kind of event in computer, we usually follow event-driven paradigm or event-callback.
The idea is there is an event loop that waits for a new event coming into the system. This case, keyboard is an event, the event loop then calls event-callback. What event-callback does is it compares the value of input with some conditions then do some other tasks (it might change some state of the program or notify users).
The idea is keep CPU busy by either 2 ways.
event-driven : do other tasks while waiting for a new event
multithreading: multiple threads in the system. This approach has the disadvantage is at data-race
Have fun

Keep looping until user enters a blank line?

So I've run into the following problem. My goal is to create a loop that keeps taking user input over and over until the user doesn't enter anything into 'cin >>', leaves the line blank, and simply presses the ENTER key to move on, at which point the program is supposed to break out of the loop and continue on with the rest of program execution. Something like this:
do {
cout << "\nEnter a name: ";
cin >> input1;
if (input1.empty())
{
break;
}
else
{
user_name = input1;
}
} while (!input1.empty());
As you can see, I've already tried using the empty() function, but that didn't work, the program simply stays in the loop and doesn't break out, no matter how many times I press enter. It just keeps prompting me to enter a name. I've also tried using something like
if (input1 == "")
but that doesnt work either. Can anyone help? How do I break out of this loop?
UPDATE: OK guys, I've tried your recommendations, and it worked! Thank you so much! Unfortunately, although the getline function works, it has also created a new problem for me. Basically, in the first initial loop, the program prompts for a name, I type in a name, and the name is stored in user_name. However, in the SECOND loop, the program doesn't even give me the chance to enter any input, it simply prints "Enter a name: ", and then instantly exits out of the loop, and continues on with the rest of program execution. Why is this happening?
Use this getline(std::cin, input1):
while (getline(std::cin, input1))
{
if (input1.empty())
break;
username =input1;
std::cout << input1 << std::endl << "Enter Input : ";
}
Use std::getline(cin, input1); instead to read a line from the console.
Using cin directly reads exactly one word from stdin. If the user does not input anything, no word has been given and cin does not return yet (your empty check is not even executed).
After you use std::getline you can leave your empty-check as-is:
std::getline(cin, input1);
if(input1.empty())
break;
BTW: In C++ you should also check if the underlying stream has run into an error. So check the return code of cin or getline. This can be done with the following code:
if(!std::getline(cin, input1))
// I/O error
In general, looping until an empty line is entered would be:
while ( std::getline( line ) && !line.empty() ) ...
If you need a prompt: the prompt is part of the input logic, and
should be implemented as such:
std::string
getlineWithPrompt( std::string const& prompt )
{
std::cout << prompt;
std::string results;
return std::getline( std::cin, results )
? results
: std::string();
}
You then do something like:
std::string line = getlineWithPrompt( "prompt for first line" );
while ( !line.empty() ) {
// ...
getlineWithPrompt( "prompt for further line" );
}
(This is actually somewhat simplified, as it treats hard errors
on input, end of file, and empty lines identical, which is
rarely the right thing in professional software. But for
learning purposes, it should be sufficient.)
Cin won't read the whitespace that you call an empty line. Getline may do this, but I am not entirely sure. You could define an end character that the user would type and check for that. Gets would also work, it will just set the starting character to 0x0. Be careful with gets(), it is prone to allow buffer overflows.
This works as well:
char line[128];
do
{
cout << "Enter something: ";
gets(line);
} while (strcmp(&line[0], "\0") != 0);
#JamesKanze
So something like this to exit the while loop?
string str = "foo";
while (str == "foo"){
getline(cin, str);
}
str = "foo";

While loop doesn't end

I rewrote this loop in several ways, with nested Ifs and do whiles, yet behavior is the same. It behaves as expected as long as the user does not enter a character or a string. Once the user does it just goes on spinning the loop until I CTRL+C it.
From what I have researched, when a variable is a number and the user inputs a char or a string, they just get converted into their ASCII numbers, in which case the while check should work. The number should be larger than allowed and the user should be prompted for a new value right? Why does it keep looping infinitely?
Width is declared as a float.
void setWidth ()
{
std::cout << "\nPlease enter the width (use numbers greater than 0 and no greater than 20.0).\n";
std::cin >> width;
while (width <= 0 || width > 20)
{
std::cin.clear();
std::cin.ignore();
std::cout << "You have entered a number outside of the allowed range.\nPlease enter a number greater than 0 and no greater than 20.\n";
std::cin >> width;
}
}
Like I said, for numbers it works great, doubles, negatives, whatever. But something like "asdf" or "a" will put it in infinitely spinning loop.
It seems like I've tried everything. Why does this happen? I mean I know why it loops, it's because the number is not between 0 and 20, but why does it not ask user for input? I do clear the buffer.
The line std::cin >> width; fails because the input isn't a number. It also doesn't consume any of the input, so you are stuck in an infinite loop.
To avoid this, you should read the input using std::getline(), then try to convert it (std::ostringstream is one option), handling and reporting failures accordingly.
The default for cin.ignore() is to ignore just a single character.
If you want to ignore longer strings, you have to add extra parameters for that, perhaps cin.ignore(1000, '\n') which skips up to 1000 characters or the next newline (whichever comes first).
cin::clear() "Sets a new value for the error control state" 1, but the remaining input is still here and still read.
Then I guess the actual behavior depends on the compiler since when I compile it with g++ 4.6.3 and type the input "abc", it only loops three times and then wait for another input.
To empty the cin buffer you may rather see How do I flush the cin buffer?
Try checking the failbit on cin
Ok, thanks for all the help guys... I finally managed to get it to work with cin (not getline), by doing exactly what ive been doing, except I made a clearBuffer() function. So instead of clearing the buffer from within the getWidth function, the getWidth function calls another function.. thereby leaves the getWidth function to execute some code... then comes back to run the rest of it...
For some reason when it goes outside of the function it works fine and strings and chars trigger the error.. but if the cin.clear and cin.ignore are kept within the function then I have that problem.
So the final code looks like this.
void clearBuffer()
{
std::cin.clear();
std::cin.ignore(80, '\n'); //Ignore the first 80 characters up to an Enter character.
}
void setWidth ()
{
std::cout << "\n\t\tPlease enter the width.\n(use numbers greater than 0 and no greater than 20.0).\n";
float temp = NULL; //Using temp here so that we dont write invalid characters to an actual variable.
std::cin >> temp;
clearBuffer();
while (temp <= 0 || temp > 20)
{
std::cout << "\nERROR: You have entered width outside of the allowed range.\nPlease enter a number greater than 0 and no greater than 20.\n";
std::cin >> temp;
clearBuffer();
}
if(temp > 0 && temp <= 20)
width=temp;
}

C++ cout print twice in do while loop

The system did this:
Please input the Full Name of the user:Please input the Full Name of the user:
It output the string "Please input the Full Name of the user:" twice , how do i change the code to make it just cout once
string fullname = "";
do
{
cout << "Please input the Full Name of the user: ";
getline (cin,fullname);
}while(fullname.length()<1);
C++ What is causing the system to output twice
You could try flushing your input stream to get rid of leftover newlines:
std::cin.ignore(x);
(with x being the number of characters to ignore, e.g. INT_MAX).
Simple solution would be to move the std::cout statement outside of the do-while loop.
string fullname = "";
cout << "Please input the Full Name of the user: ";
do
{
getline (cin,fullname);
}while(fullname.length()<1);
You are performing an input operation without checking the result, which is a hard programming and understanding error. Do this instead:
for (std::string line; ; )
{
std::cout << "Name: ";
if (!std::getline(std::cin, line) || !line.empty()) { break; }
}
The first condition checks whether the input succeeded (which is false when the input stream is closed), and the second checks whether the read line is non-empty. The short-circuit semantics of || make the second check legal.
As others have pointed out the problem is that you have an extra '\n' character on the input stream.
Contrary to the popular answer I don't think flushing (ignore()) the current input is a good solution. You are treating the symptom not the problem. If you are using ignore() you are potentially throwing away user input that you might actually want or something that could have detected an error from the user:
> Input Your age
> 36xxxx
// If you use
std::cin >> age;
// Then sometime later in your code you use
// ignore to make sure that you have "correctly" skipped to the next new line
std::ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// You have now just ignored the fact that the user typed xxx on the end of the input.
// They were probably doing that to force an error in the code or something else erroneous
// happened but you just missed it with std::ignore()
The best solution is not to get into this situation.
This problem is caused by using a combination of operator<<() and std::getline() to parse user input. I love using operator<<() to parse normal or regular input; but manual user input (ie Question/Answer) is harder to predict and users input is line based (there input ends at the '\n' character because the buffer is flushed when they hit <enter>).
As a result when I parse manual user input I always use std::getline(). This way I know I got the whole of their answer. It also allows me to validate the input to make sure there was not a typing error.
std::cout << "What is your age\n";
std::string line;
std::getline(std::cin, line); // Get user input
// Use stream for easy parsing.
std::stringstream linestream(line);
// Get value we want.
linestream >> age;
// Validate that we have not thrown away user input.
std::string error;
linestream >> error;
if (error.length() != 0) { /* do stuff to force user to re-input value */ }

How do I use a loop to display a menu and re-prompt for input?

I want to have a menu display that accepts user input. However, I want the user to be able to go back to the beginning of the menu to reselect options.
while(end != 1) {
display menu options
prompt user for input
if(input == x) {
do this
}
else
do that
}
then, i want it to skip back up to the beginning of the loop and ask the question over again. Howcan I do this without creating an infinite loop of the menu printing across the screen?
Unfortunately you didn't really show the code you are using but rather some pseudo code. Thus, it is hard to tell what you are actually trying to do. From the description of your problem and your pseudo code I suspect, however, that the root of the problem is that you don't check your inputs and don't restore the stream to a reasonably good state! To read the menu selection you probably want to use code akin to this:
int choice(0);
if (std::cin >> choice) {
deal with the choice of the menu here
}
else if (std::cin.eof()) {
// we failed because there is no further input: bail out!
return;
}
else {
std::string line;
std::cin.clear();
if (std::getline(std::cin, line)) {
std::cout << "the line '" << line << "' couldn't be procssed (ignored)\n";
}
else {
throw std::runtime_error("this place should never be reached! giving up");
}
}
This is just a rough layout of how the input would basically look like. It would probably be encapsulated into a function (in which case you'd want to bail out of from a closed input somewhat differently, possibly using an exception or a special return value). The main part of his is to
restore the stream back to good state using std::isteam::clear()
skip over the bad input, in this case using std::getline() with a std::string; you could also just std::istream::ignore() the remainder of the line
There may be other problems with your menu but without seeing concrete code I'd think it is hard to tell what the concrete problems are.
Instead of using a while, consider using a function, so you can call it where you need it:
void f()
{
if(end != 1) {
display menu options
prompt user for input
if(input == x) {
do this
f();
}
else{
do that
f();
}
}
}
I am not sure what your looking for either but this is some rough code of a menu
while(1){
cout<<"******* Menu ********\n";
cout<<"-- Selections Below --\n\n";
cout<<"1) Choice 1\n";
cout<<"2) Choice 2\n";
cout<<"3) Choice 3\n";
cout<<"4) Choice 4\n";
cout<<"5) Exit\n";
cout<<"Enter your choice (1,2,3,4, or 5): ";
cin>>choice;
cin.ignore();
switch(choice){
case 1 :
// Code for whatever you need here
break;
case 2 :
// Code for whatever you need here
break;
case 3 :
// Code for whatever you need here
break;
case 4 :
// Code for whatever you need here
break;
case 5 :
return 0;
}