Yet another C++ cin loop issue - c++

Update
I found the cause of the problem. I have been experimenting with the fish shell. I saw the comment that said someone had successfully run my code on a Mac, and decided to try it in a standard bash shell. It worked perfectly. So, no more fish shell I guess. :)
I would still appreciate knowing how and why cin works the way it does. This is the main part of my question.
I have run into a popular problem: using cin in a loop. The code is straightforward, but I cannot find a solution. The answers Google have provided me are varied, but usually involve some combination of cin.clear(), cin.ignore(), and cin.get(). Unfortunately, I haven't been able to find a combination or ordering of those that fix my problem. Moreover, I find it frustrating that I don't have a complete understanding of the function of cin. I'd rather not use trial and error to fix this. I want to understand exactly what's going on.
What Should Happen
When I run my code, I should see a prompt with a list of options. I should be able to type a character which will run one of the options. Then, it should display the prompt again and repeat the process until I select the Exit option.
What Actually Happens
As soon as I run the code, it prints the prompt to the screen an arbitrary number of times and eventually stops halfway through the prompt. Then I am unable to do anything but kill it with ^C.
$ ./run
Choose an option:
[A]dd a score
[R]emove a player
[E]xit
: That is not a valid input.
[repeated a bunch of times]
Choose an option:
[A]dd a score
[R]emove a player
[E]xit
: That is not a valid input.
Choose ^C
$
My Question
What causes cin to do that? As an experienced Java developer (but a beginner C++ developer), I'm familiar with the concepts of buffers and streams and such, but I have no idea how cin works. I know that cin.clear() clears an error state, and cin.ignore() ignores a number of characters in the stream. My Google-fu has thus far been unable to find a concise reference.
Why does cin act the way it does? How should one visualize what happens under the hood when using cin in a loop? What is the most elegant way to implement this infinite menu idea in C++?
My Code
Here is a simplified version of my code, which produces the exact same problem as the full version:
#include <iostream>
using namespace std;
int main () {
//infinite menu
char input;
while(true) {
//prompt
cout << "\n\nChoose an option:\n";
cout << "[A]dd a score\n";
cout << "[R]emove a player\n";
cout << "[E]xit\n";
cout << "\n\t: ";
//input
cin >> input;
//decide what the input means
switch(input) {
case 'a':
case 'A':
cout << "Add a score.\n";
break;
case 'r':
case 'R':
cout << "Remove a player.\n";
break;
case 'e':
case 'E':
cout << "Program Complete.\n";
return 0;
break;
default:
cout << "That is not a valid input.\n";
}
}
return 0;
}
I compile and run with:
$ g++ Test.cpp -o run
$ ./run
I'm running gcc version 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00) on Mac OS X 10.8.2.

Do yourself a favour and don't extract tokens directly from std::cin. Instead, read line by line with getline and then interpret each line. Also, you must always evaluate the result of an input operation in a boolean context, or you will not be able to handle arbitrary input correctly.
For a test, your program must survive if you call echo "abc" | ./run. This should always be one of your first tests.
Now, on to the code:
#include <string>
#include <iostream>
int main()
{
for (std::string line; std::getline(std::cin, line); )
{
if (line.empty()) { continue; }
if (line == "A" || line == "a") { /* ... */ continue; }
if (line == "R" || line == "r") { /* ... */ continue; }
if (line == "E" || line == "e") { break; }
std::cout << "Sorry, I did not understand.\n";
}
std::cout << "Goodbye!\n";
}

Related

Unable to detect enter key in C++

Now, before this question gets marked for duplicate. I have already gone through most of the questions and their relative answers of C++. These are the links that I have tried and none of them work for me. It maybe because they are using an older version of C++, and I have the latest version of C++. Here are the links that I have tried:
Detecting ENTER key in C++
https://www.sololearn.com/Discuss/1863352/how-can-i-check-that-user-press-enter-key-in-c
http://www.cplusplus.com/forum/beginner/2624/
https://www.dreamincode.net/forums/topic/398680-detect-enter-key/
Now, with the duplicates out of the way. I am making an expression calculator. So, for example if the user input is: 2+2*6*9/9, then the output should be 14.
The code where I suspect that the problem lies is in:
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::string;
using std::vector;
void clear();
void error(string message);
int main() {
cout << "Enter an expression: ";
double l_Value = 0, r_Value = 0, result = 0, count = 0, previous_number;
char op;
while (cin >> l_Value) { // 1+2*3+6-4/2+3
if (!cin) {
error("Invalid operand entered!");
}
else {
bool is_Error = 0; // false
vector<double> numbers;
numbers.push_back(l_Value);
previous_number = l_Value;
while (cin >> op) {
if (op == '\0') {
break;
}
cin >> r_Value;
switch (op)
{
case '+':
numbers.push_back(r_Value);
previous_number = r_Value;
break;
case '-':
numbers.push_back((-1 * r_Value));
previous_number = (-1 * r_Value);
break;
case '*':
numbers.pop_back(); // take out the number
r_Value *= previous_number;
numbers.push_back(r_Value);
previous_number = r_Value;
break;
case '/':
if (r_Value == 0) {
error("Sorry, division by zero has occured. Please re-evaluate your expression!\n");
is_Error = 1; // true
break;
}
else {
numbers.pop_back(); // take out the number
previous_number /= r_Value;
numbers.push_back(previous_number);
break;
}
}
}
if (!is_Error) {
for (int i = 0; i < numbers.size(); i++) {
result += numbers[i];
}
cout << result << '\n';
}
numbers.clear();
result = 0;
l_Value = 0;
r_Value = 0;
}
cout << "Enter an expression: ";
}
clear();
return 0;
}
None of the links above seemed to work for me.
When I press the Enter key, it expects me to give another input, and that is not supposed to happen. So when I used cin.get() == 'n' or cin.get() == (int)'\n', it expects for another input. But, when I have an 'x' at the end of the expression, it works perfectly fine. So, I need the "cin" operator to help me detect an Enter character at the end of the expression and then terminate the program.
Here, is a sample run of a program with 'x':
[![running as x-terminator][1]][1]
[1]: https://i.stack.imgur.com/ORPQa.png
When I try the above solution such as "cin.get() == '\n':
Then, I thought that maybe it is reading the null character and so, I tried if (op == '\0'):
For the enter key and null character I had to press Ctrl+Z to terminate the program. Please help!
As, mentioned by user #idclev, I already have a string program that works, but I am trying to avoid using string to calculate any expressions! So, if I could detect an enter key pressed using a character datatype that would be great!
I avoided strings to avoid parsing through the text
That argument is moot. What you can read from cin you can also read from a std::string, no difference whatsoever. You just need to add one step:
#include <iostream>
#include <string>
#include <sstream>
int main( ){
std::string x;
std::cin >> x;
if (x == "") {
std::cout << "user pressed enter (and nothing else)";
} else {
double y;
std::stringstream ss{x};
ss >> y;
std::cout << y;
}
}
This will read one std::string. If user only hit enter then the string will be empty. If the user entered something the else branch will be taken and you can extract the number from the string in the same way you did extract the number from cin (via using a std::stringstream).
If you have more than one number in the input you need to use getline to read the string, because cin will (by default) only read till the next whitespace.
Again...
If I used a string, I would have a tough time in extracting single-digit and two-digit or n-number of digits in a string. The double data type does that for me
You can read single-digit or any number of digits from a stringstream in exactly the same way as you read them from cin.
I already made a program with string in it. I was trying to avoid string to see how much faster would it be without string.
It won't be any faster. Constructing the string and the stringstream is maybe in the order of microseconds. A user entering input is in the order of seconds, maybe milliseconds when they are typing very fast.
Your approach cannot work because hitting enter is not considered as a character. Trying to read a character when there is none in the stream will fail. It will not set the character to \n or \r.
On the outer loop, you are trying to read a double, but you keep pressing enter. There is no input to evaluate, so it keeps trying to read a double. You can get out of it by ending the input stream with ^Z, or you can give it any actual content to read, and it will try to make it into a double (which is what your code explicitly told it to wait for).
Basically, when you press enter, it's ignoring it because
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
Extracts as many characters as possible from the stream and inserts them into the output sequence controlled by the stream buffer object pointed by sb (if any), until either the input sequence is exhausted or the function fails to insert into the object pointed by sb.
Try experimenting with this to see what is happening.
#include <iostream>
#include <vector>
#include <string>
int main() {
double x;
std::cin >> x;
std::cout << "read this value: " << x << std::endl;
// this is what while or if will look at
bool success = !std::cin.fail();
if (success)
std::cout << "success" << std::endl;
else
std::cout << "failure, loop will exit" << std::endl;
return 0;
}
What you should want (in my opinion) is a function that takes the expression as a string, and returns the result, so you can write unit tests, and make sure the function works. You can use this function with any expression that you can put in a string. It doesn't HAVE to be typed in by a user.
If you want the user to type in the experession, it's a lot easier to just use getline() then pass the string to your function. The big problem with using cin on each variable and character is that the user has no idea which datetype is expected right then. Granted, it's not hard to guess with an expression, but you wrote it and debugged it and still didn't know which cin you were failing to get the right datatype to. (this is normal, btw -- been there, which is why I getline and parse separately)

While loop carries on forever (C++)

I'm still quite new to c++ and just experimenting with the language.
I have recently created a 'tictactoe' game.
I have created this simple looking function to get the users board position (from 1 to 9). It seems to work fine but I found a weird bug so to call it;
Whenever I enter a 12 digit number or higher the loop just carries on forever printing 'Invalid position!' and on to the next line 'Choose your position 1-9: '.
I am using visual studio to write code. Is it something with the code or is it perfectly fine? I'm eager to find out to learn from it.
Here's the function:
int getUserPosition()
{
int position;
while (true)
{
cout << " Choose your position 1-9: " << endl;
cin >> position;
if (position < 1 or position > 9)
{
cout << "Invalid position!" << endl;
}
else if (board[position - 1] == 'X')
{
cout << "This position has been taken!" << endl;
}
else
{
return position;
break;
}
}
}
I finally understand the actual behavior here. This is not invoking undefined behavior but rather defined behavior you don't want.
cin >> position;
This tried to read your 12 digit number, which didn't fit into an int, so the read failed. Because it failed on a format error, the 12 digit number remained in the buffer, so the next pass around the loop tried to read it again.
Always use cin::getline() when you intend to read keyboard input. The error/cleanup logic in cin is not designed to resync keyboard input, but rather to resync input piped from a generator that can't read your error messages. In the future, when you try to use cin with a pipe, the best solution is to check cin::fail() and bail the program if it ever gets set.

C++ if condition not checked after goto

I'm working on a simplish game (this isn't the whole code, just the bit that I'm having issues with) and I've run into this issue; After the condition is furfilled, it goes back to the start and it offers me to reenter the string, however, whatever I enter, I just get 'Not Valid'. Does anyone know why? I'm using the GNU C++ Compiler.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string command;
mainscreen:
cout << "blab";
getlinething:
cin.ignore();
getline(cin, command);
if (command == "task")
{
goto mainscreen;
}
else
{
cout << "Not valid.";
goto getlinething;
}
return 0;
}
When I run your code with a debug print it shows that each time you read a new command you are loosing the first char of the string. In fact, when I remove your cin.ignore() it works fine.
Also, have a look at this while to see if it fits your needs:
cout << "blab";
while(1){
getline(cin, command);
if(command == "task"){
cout << "blab";
getline(cin, command);
}
else{
cout << "Not valid.";
}
}
For debugging purpose at least, why not do
cout << "'" << command << "' Not valid" << endl ;
Alright, I tested it out. Without cin.ignore(), I cannot enter the data into the string at all.
The first time I enter it captures everything. So if I wrote task, the string would say 'task', however the second time I entered it, it would say 'ask'. I don't really know why it's doing that.
The cin.ignore() line will always discard one character by default (unless it encounters EOF, which would be a fairly deliberate act on cin).
So, let's say the user enters task and then hits the enter key. The cin.ignore() will discard the 't', and the command string will contain "ask". If you want to get a match, the first time through, the user will need to enter ttask. The newline will be discarded, in either case. The same will happen until a match is encountered.

CTRL+D suddenly stopped working in Mac OS X Terminal, will not perform EOL operation

I have basic code that I am trying to run in terminal for a class. I am having trouble ending the code with the ctrl+d command once I am done typing. The code looks for the amount of certain characters, "e", vowel as well as counts total characters used. For hours yesterday I was able to use the Ctrl+D command to end my program and continue to edit/add to it but it stopped working suddenly.
I have noticed that when a string of "d"'s are inputted into the window, the return key is hit, and then ctrl+d is used, the programming successfully displays the data but otherwise any other input does not seem to give the EOF command that I am looking for.
I have tried resetting my terminal, saved the condition in which the "d" string worked and tried again. What is going on? After reading extensively on the topic I think it may be due to something else running in the background?
int main() {
char ch;
int ecount=0, vowels=0, other=0;
cin.get(ch);
while(!cin.eof()) {
switch(ch) {
case 'e':
ecount++;
case 'a';
case 'i':
case 'o':
case 'u':
vowels++;
break;
default:
other++;
}
cin.get(ch);
}
cout << ecount << " "<< vowels << " " << other << endl;
}
You should not loop testing only eof. There are other ways for the stream to error. Just loop like this:
while( cin.get(ch) )
{
// ...
}

cin and switch odd behaviour

So I'm having some problems when using cin and switch statements.
First, the program prompts for an int:
cout << "How many registers would you like to use?: ";
cin >> kassor;
Later on, the user is asked to make a choice:
cout << endl << "Press \"S\" to run the queue simulator and/or make a timestep." << endl;
cout << "Press \"Q\" to quit." << endl << endl;
cout << "Choice: ";
cin >> choice;
switch (choice)
{
case 's':
case 'S':
{
cout << "test";
nya = newCustomers();
break;
}
case 'q':
case 'Q':
{
return 0;
}
}
Here, the 'q' option works fine, but the 's' option does not. It 'hangs', as if still waiting for input. I have tried various cin.ignore() and such, but to no avail.
What puzzles me is that
switch (choice)
{
case 's':
case 'S':
{
cout << "test";
nya = newCustomers();
break;
Gives nothing, but the following:
switch (choice)
{
case 's':
case 'S':
{
cout << "test";
cin.ignore(1024, '\n');
nya = newCustomers();
break;
outputs 'test'.
My main question here is: Is the problem cin or something in the case: s ?
Thank's in advance :
It looks like the function newCustomers is getting hung up on a stray character or two after the input to choice. That would explain why the ignore call "fixes" the problem, and it's the solution suggested in the comment by #TheBuzzSaw.
To see this more clearly, change
cout << "test";
to
cout << "test\n";
or to
cout << "test" << std::endl;
On some systems the console is line-buffered, so you won't see any output until the program writes a newline. Inserting endl flushes the output buffer, so you should see the message even if subsequent code hangs. Or change it to:
cerr << "test\n";
cerr is more aggressive about flushing buffers, precisely because it's used for error output that you don't want to miss.
Short Answer:
I believe cin is failing somewhere or it is the cause of unexpected behavior
I cannot pinpoint it without more code.
Edit: I cannot post a comment on your post, so I figured I would post here. The "hanging" could be an infinite loop. If you are doing something like what I am doing and looping to get input and fail to clear the error bits cin will constantly fail. If you are not cout'ing something each time you ask for input it could just be quietly sitting there looping through that input-gathering function. Put breakpoints in all of your loops and step through with the debugger to verify none of your loops are infinite looping.
Try adding a std::cin.clear(); before the .ignore() in your second test case. See if that stops your hanging.
Explanation:
cin can fail. This can cause weird behavior. A common way for it to fail is if you are reading into an integer and you get character input. Once cin fails it sets a fail bit and from then on, cin does not behave like you would expect.
I would recommend not using a bare cin >> choice, because it can fail and you wont know it. I would abstract this out to a method that gets the proper input you want.
I personally keep a tiny utility library(.h) and .cpp around to include in projects where I am using common functionality I have already coded.
I have a readIntBetween() function which accepts 2 integers and reads from standard input an integer between those two numbers. If the user does not provide the right input (integer over or under bounds, or input containing a character) I ask them to re-enter the input.
In this function I make sure to clear the fail bits when I have detected a failure, and I ignore something like 200 characters to "flush" it out.
Here is the code to my readIntBetween function. I hope it helps you diagnose your error and fix it:
int readIntBetween(int lower, int upper, std::string prompt)
{
bool goodVal = false;
int value = -1;
do
{
std::cout << prompt ;
std::cin >> value;
if ( value >= lower && value <= upper)//check to make sure the value is in between upper and lower
goodVal = true;
else
{
if(std::cin.fail())
{
std::cout << "\tError - invalid format for integer number" << std::endl;
//clear all status bit including fail bit
std::cin.clear();
//flush input buffer to discard invalid input
std::cin.ignore(1000, '\n');
}
else
std::cout << "Value is not valid, must be between " << lower<<" and "<<upper<<"."<<std::endl;
}
}while(!goodVal);
return value;
}
If your cin is being used inside a loop, I recommend a different approach.
char buffer[64];
cin.getline(buffer, 64);
char choice = buffer[0];
switch (choice)
{
...
}
It is possible your cin is not being reset, and any extraneous characters are being fed into the subsequent requests for input. Grab more input and only process its first character.