C++ do...whille loop duplicate prints with getchar function - c++

The code below is printing "Menu" twice when input is different from 3.
do{
puts("Menu");
option = getchar();
}
while (option != '3');

A quick fix:
do{
puts("Menu");
std::cin >> option;
}
while (option != '3');

You just need to flush your stdin. When your program reaches getChar, it finds the newline character, and processes it as an input character.
if your not set on using getChar() to retrieve the input a better option would probably be to use std::cin, as it deals with white space such as this more intelligently
You can also flush the input by adding the line fseek(stdin,0,SEEK_END); right before you retrieve the character from the input.
or you can run an if statement to check if the character retrieved is newline
if ( option != '\n' ) {
...
}
also see this answer Using getchar() on c gets the 'Enter' after input

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

While loop with getline doesn't end for user input

I thought getline stops at a newline character, but the while loop does not end? it returns the correct data but it just sits in the terminal window. For example:
Enter an expression: #5+4#5+4
(blinking cursor)
(can enter data forever and press enter forever and it wont exit)
my code, (main.cpp):
int main()
{
string exp;
cout << "Enter an Infix Expression:";
while (getline(cin, exp, '#'))
{
string token = exp;
string post;
cout << token << endl;
IntoPost *infix = new IntoPost(token.length());
post = infix->inToPost(token);
cout << post << endl;
}
cin.get();
}
The Solution Using EOF
Your current program is looping endlessly because getline returns std::basic_istream, so while(getline()) will never equate to 'false'.
As #0x499602D2 has stated, your program is working as intended, but the extraction from getline can only end in two ways, as indicated by the reference here:
Extracts characters from is and stores them into str until the delimitation character delim is found (or the newline character, '\n', for when no delimiter is specified).
The extraction also stops if the end of file is reached in is or if some other error occurs during the input operation.
The first condition is difficult to pull off, as inputs on console are triggered by the \n character.
As for the second condition, as per #DavidC.Rankin:
You can also generate a manual EOF on Linux with [Ctrl+d] or windows with [Ctrl+z] (generally twice is required)
This means the solution is to use [Ctrl+d] or [Ctrl+z] to trigger the second condition to end your while loop at any time.
Alternative Using a Break Statement
One alternative way you can try to end the loop instead is breaking on input of an 'exit' string:
(1)
#include <algorithm>
//...
while (getline(cin, exp, '#'))
{
// removes meaningless endline chars from input
exp.erase(std::remove(exp.begin(), exp.end(), '\n'), exp.end());
if (exp == "exit"){
break;
}
//... Your While Block Code Here!
}
To break out of your while loop, you can simply use:
exit#
# Note, the endls from your couts in the loop will bleed into your inputs on your next while (getline(cin, exp, '#')), giving us unwanted newlines. To prevent this, we can get rid of the endlines from the inputs by using std::erase(). If you wish to keep those endlines in your input, simply set string token = exp; in front of the erase() line.
That's right, getline blocks the execution of the loop until a line separator is received and returns while that all is well, in the next step everything is repeated. If you want the loop not to be infinite - then put the Boolean variable key in the loop condition, and from the input check if the last character is an exit symbol and if so switch the variable key

C++, user input check for '\0' stops at spaces?

If the user inputs a sentence containing spaces the while loop stops at one of these spaces. Why is this happening? are '\0' and a space the same or did i do something else wrong?
int main ( )
{
char user_input[200];
cin>>user_input;
int i=0;
while(user_input[i]!='\0')
{
i++;
}
cout<<i;
return 1;
}
Thanks everyone, I appreciate your help.
\0 is the null terminating character with ASCII code 0.
Space is another character with ASCII 32 i suppose.
In fact you are doing this.
cin >> user_input;
It takes input till you press space or enter. So no space is present in your user_input string.
Use this instead of cin.
cin.getline (user_input, 200, '\0') ;
This is an issue with reading using >> into a char array. It splits at whitespace when tokenizing. Try printing user_input to screen to confirm this.
Using getline into a std::string is generally safer in this context (as mentioned by daknøk). And I assume the input is likely to be terminated by a carriage return?
std::string user_input;
std::getline( std::cin, user_input, '\n' );
This is because your input stops reading when white space is entered. You can use
cin.unsetf(ios::skipws)
By default it is set to skip white spaces. With this you will get your desired result.

How to read from std::cin until the end of the stream?

My problem is, that I want to read the input from std::cin but don't know how long the input is. Also I have to char and can't use std::string.
There are two ways I have to handle:
a) The user inputs text and when he hits [ENTER] the program stops reading.
b) The user redirects std::cin to a file (like .\a.oput < file) which can hold multiple lines.
Edit: Just noticed that std::cin.eof() is always false also in the case of reading form a file.
For a) I could read until \n occures. For b) Edit: No (I could read until std::cin.eof() occures.)
But when I don't know whether I'm getting an a) or a b) problem, how can I break the reading process?
This is what I have for a) ...
char buffer = ' ';
while(std::cin >> std::noskipws >> buffer && buffer != '\n')
{
// do some stuff with buffer
}
... and b)
char buffer = ' ';
while(std::cin >> std::noskipws >> buffer)
{
// do some stuff with buffer
}
Also I know there is std::cin.tellg() to get the current position in the stream.
Edit: So it seems like in case of the file the input streams gets terminated, in the way that std::cin >> std::noskipws >> buffer gets false.
What the code above does for a):
It waits for the user to make an input and press [ENTER]
Then it loops through every char entered by the user on the last line.
Then it waits again for the user to make an input and press [ENTER]
Infinite-waiting-processing-loop
So how do I do it?
You could require the input to always end EOF (meaning from commmand line requiring ^D to be pressed) and then use the process for b as always. This would then enable multiline input from cmdline as well
You could use the (old) getline function, which takes a pointer to a char array and can use a delimiter. But you wont be able to ensure that in every case it will read to the eof (as the char buffer might be too small), but using a char-array and not paying attention to the size of it is a very dangerous (and from the point of security catastrophic) thing anyways as it can lead to buffer-overflows which can be easily exploited.
This code should enable you to extract line by line from the input:
char buffer[256];
while(getline(buffer,256,'\n')) { //get a line
/* do something with the line */
}
This to read a maximum amount of chars:
char buffer[256];
while(getline(buffer,256)) {//get a maximum amount out of the input
/* do something with the line */
}

End of File(EOF) of Standard input stream (stdin)

Does stdin have any EOF? For example, if I start reading from stdin using fread or read, then will the following loop end?
while ((c = read(0, buffer, BUFSIZ)) > 0) {
.
.
.
}
If the answer to this question is no, then is there any way to add EOF to stdin?
Speaking about EOF in stdin: when you redirect input from file, e.g.:
program <input.txt
the file already has an EOF, so this is not a problem. In console you can simulate EOF flag. In UNIX systems it is Ctrl+D, in Windows Ctrl+Z. When you type this in the console, program will behave like it has just reached end of input file.
Edit
According to a question asked by OP:
So does it means that stdin don't have EOF and we have to insert them manually using Ctrl+Z or Ctrl+D?
Actually -- yes. One may consider stdin (not redirected, but taken from the console) as infinite file -- no one can tell where does it end. The end of input file, where input ist stdin, must be told literally by Ctrl+D or Ctrl+Z.
I have never programmed C in windows so I can't tell you but in bash, the program will get an EOF when you type end of data (Ctrl+D)
while ((c = read(0, buffer, BUFSIZ)) > 0) {
You don't say the type of c but using that name implies that it's a char. Note that the EOF value for iosteams is an (int) -1. Storing that into an unsigned char will get you a value of 255 which will not match EOF.
The way to test for EOF is to check the return value of fread, and then use feof:
while( fread( ... ) ) { // loop so long as fread does not return zero
// do something
}
if ( feof( stdin ) ) {
// read failed because of EOF
}
else {
// some other error
}
Your solution is tagged C++, so here's some C++.
std::string lols;
while(!(std::cin >> lols).eof()) { // This loop will end when EOF is reached
// Process string
}
First getchar() is really getc(stdin) so getc(FILE) you can read more from that. getchar() gets you last unprocessed character from input stream or stdin pressing enter is '\n'. if the stdin is empty getchar forces a pause to get input.
Say in a program I call getchar() at first the stdin is empty so it pauses for input. If I enter ab'\n' the first getchar() will get 97 the ascii of 'a'. the next time i call getchar() i will get b , then again getchar() will have '\n'.
To prove this write this code.
int choice;
do
{
cout << "Enter input:" ;
choice = getchar();
cout << "Last getchar(): " << choice << ":" << (char) choice ;
if( choice == '0' || choice == EOF)
{
cout << "Exited loop" << endl; // EOF is ctrl+z in windows
break;
}
}while(true);
I do believe stdin is a global so until getchar() or similar function gets called it to clear the stream the characters remain there which can cause bugs later if you use getchar() elsewhere. As people have mentioned you can use gets(char[]) which puts all characters until newline into the character array. The problem with this is you need a char[] larger than input or you will get errors. The nice thing is gets(char[]) does clear stdin so you can make a dumby buffer to clear stdin or process it.
I hope this is informative.