cin.get() not functioning as desired [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Program not waiting for cin
I wrote the following code:
#include <iostream>
using namespace std;
void search(int pre, int a, int b, int x) {
char c;
cout << "Is the number " << ((x == 2) ? b : a) << endl;
c = cin.get(); ////// this does not block
if (c == 'y') return;
else {
cout << "Is the number " << ((x == 2) ? b : a) << " closer to your number than " << pre;
c = cin.get();
if (c == 'y') {
search(a, a, (a + b) / 2, 2);
} //c=='y'
else search(a, (a + b) / 2, b, 1);
}
}
int main() {
int N;
cout << "Enter N? ";
cin >> N;
search(N, 1, N, 1);
return 0;
}
No need to worry if you don't understand the logic because my question is not regarding that.
In the search function, there are two cin.get(), where i need the user to enter a character. My problem is that the the program blocks for input only after the second cin.get().
For example:
Is the number 7 //program doesn't wait after this
Is the number 7 closer to your number than 8 //program blocks here for an input
Why does it do so?

There are at least two problems in your code. The first is that you're
leaving characters in the buffer after inputting N. The simplest
solution is to just add a call to std::cin.ignore( INT_MAX, '\n' );
after std::cin >> N;; a better solution (because it allows for more
error checking) would be to use std::getline to read the complete
line, then parse it using std::istringstream.
The second problem is that you're assigning the results of
std::cin.get() into a char. std::cin.get() returns an int,
which may be EOF. And you really want to check whether it is EOF
before converting the int to char: you cannot check after because
either some legal char will compare equal to EOF (plain char is
signed), or the char will never compare equal to EOF (plain char
is unsigned). The other alternative is to do something like:
if ( !std::cin.get( c ) ) {
// EOF or error seen...
}
each time you want to read a char. (This might be better in your
case, since if you do read EOF, all further calls to std::cin.get()
will return EOF.)

Related

C++ Code not working due to ios_base::sync_with_stdio(false). Make this work or suggest other code for taking I/O in Fastest way

#include <iostream>
using namespace std;
inline void fast(int &n)
{
n = 0;
register int c;
bool negative = false;
c = getchar();
while((c < 48 || c > 57) && c != '-' )
c = getchar();
if(c == '-')
{
negative = true;
c = getchar();
}
while(c > 47 && c < 58)
{
n = (n<<1) + (n<<3)+ c - 48;
c = getchar();
}
if(negative)
n *= -1;
}
int main ()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int a,b;
string s;
fast(a);
fast(b);
cin >> s;
cout << a << " " << b << "\n";
cout << s;
return 0;
}
I WROTE THIS CODE FOR FASTEST INTEGER INPUT USING getchar() AS WELL AS OTHER INPUTS FAST using CIN IN COMPETITIVE PROGRAMMING.
INPUTS :
1. 1 2
hello
(inputs not in a single line)
this works, here 'enter' is pressed before giving input 'hello'.
2. 1 2 hello
(inputs in a single line)
not working after pressing 'enter'. Has to give input again. It works perfectly well without ios_base::sync_with_stdio(false).
This is BREAKING the Code by removing the sync.
IS THERE ANY WAY TO SOLVE THIS AND MAKE 1 2 HELLO WORK
SO AS TO TAKE INPUT IN THE FASTEST WAY
or SUGGEST ANY OTHER METHOD or CODE !!!
Also can you please suggest Fastest method for INPUT and OUTPUT of INTEGERS as well as STRINGS for Competitive Programming!!!
This happened to me a month ago. You should not use NULL in cin.tie() and cout.tie() instead use '0' inside it.
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
This should work fine.

Why do fflush(stdin) have no effect on the output? [duplicate]

This question already has answers here:
Using fflush(stdin)
(7 answers)
Closed 3 years ago.
I wrote this simple addition software, in which I wanted the addition to end when the user entered 'n'. My current code works just fine. But I made two more variations of the same code, one worked, and one gave me an error. Can anyone tell me what is happening exactly in each case?
int a, b=0;
cout<<"Welcome to my Addition Software!!\n\n";
do{
cin>>a;
b+=a;
}while(getchar()!='n');
cout<<b;
//works just fine
int a, b=0;
cout<<"Welcome to my Addition Software!!\n\n";
do{
fflush(stdin);
cin>>a;
b+=a;
}while(getchar()!='n');
cout<<b;
//this one works too
int a, b=0;
cout<<"Welcome to my Addition Software!!\n\n";
do{
a=getchar();
b+=a;
}while(a!='n');
cout<<b;
//doesn't work
I wanna know why fflush(stdin) have no effect on the code. If I just keep writing my input like "20, 30, 50, n" instead of "20, y, 30, y, 50, n" I get the same result in both working codes. Why does this happen?
First of all, it is best to use C++ standard input and output std::cin and std::cout respectively.
The main problem with your code is that it conflicts with types you want:
You want to add integers int together and to see if the input is the character char 'n'.
What's happening is the legacy C fflush(stdin) "flushes" or clears the standard input stream buffer (read more here: https://www.google.com/amp/s/www.geeksforgeeks.org/use-fflushstdin-c/amp/) and getchar() receives character input from the user. getchar() returns a character and by deduction, your code transmutes that input into its integral int ASCII-ANSI numerical integral equivalent.
This means that on the third version, when you input "30", what actually is collected is '3' and without flushing the buffer, the next input is considered '0' causing a problem.
I suggest you use a control structure to check if the user wants to continue before receiving input to add:
int a = 0, b =0;
char c = 0; // for y/n responses
std::cout << "Welcome to my ... "; //just finish this string
do{
std::cout << "input integer: "; // for better formatting leave at least one space after the colon
std::cin >> a;
b += a;
std::cout << "Continue? n to stop: "
std::cin >> c;
} while (c != 'n')
std::cout << "Added: " << b;

Difficulty with testing for ranges of integer values

I am writing filter program grouping kindergarten, preschool and school for ages I wrote if program but it outputs conditions wrong who is willing to take look at my program?
#include<iostream>
using namespace std;
int main() {
int input;// age
int kindergarden , preschool , school;
cin >> input;
if (2 <= 4)
{
cout << "kindergarden" << "\n\n";
if (5 <= 6)
{
cout << "preschool" << "\n\n";
}
else (7 <= 15);
{
cout << "school" << "\n\n";
}
}
}
Your first if statement is if (2 <= 4). This will always be true. 2 is always less than 4. Inside that if statement, is another if statement, asking if 5 <= 6. This will always be true also. Thus, it will output "kindergarten preschool".
I assume you want to check if input is within the two values in your if statements. To do so, you would write
if(2 <= input && input <= 4)
Also, you should bring the second if statement outside of the first. To do that, you should put your } before the second if statement, not after the last one.
Edit: As YSC pointed out, there's another issue: else (7 <= 15);. There are two issues with this:
1) It should be else if(condition), as plain else statements do not expect a condition.
2) It should not end with ;. It should end with { to hold the code that should be executed if the condition is true.
Your first if is wrapped around two others. Because you 're used flat indentation of source code, it's very hard to spot.
if (2 <= input && input <= 4)
{
cout << "kindergarden" << "\n\n";
} // here was your mistake
else if (5 <= input && input <= 6)
{
cout << "preschool" << "\n\n";
}
else if (7 <= input && input <= 15) // ; another mistake
{
cout << "school" << "\n\n";
}
You can make it into one loop actually, in a dozen various ways
#include<iostream>
#include<string>
using namespace std;
int main() {
int input = 0;// age
const struct Cat
{
int age;
string category;
} classes[] = { {2, "kindergarden"}, {5, "preschool"}, {7, "school"}, {16, ""} };
cin >> input;
// without range loop this looks tricky
for(const Cat *c = std::end(classes)-1; c >= std::begin(classes); c-- )
if ( input >= c->age )
{
std::cout << c-> category;
break;
}
}
The only advantage would be aggregation of conditions in one place. Of course, there can be more parameters for condition, e.g. upper and lower bracket instead of lower only.

Boolean condition not working properly in do-while loop

The loop in the function require() takes 3 conditions, a > b or "a" or "b" aren't digits. Even when I don't satisfy the conditions and put 2 integers in, it just loops once again.
Also when I put in a character then it just endlessly loops "Enter minimum number Enter maximum number" ignoring the cins. Anyone know why? I'm a beginner so this is probably really obvious
#include <iostream>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
int random(int minN, int maxN) //generates random number within specified range
{
srand (time(NULL));
int x = (maxN - minN);
int y = minN + (rand() % (x+1));
return y;
}
int require() //makes sure a < b and both are digits
{
int a,b;
do {
cout << "Enter minimum number" << endl;
cin >> a;
cout << "Enter maximum number. Note: Has to be greater or equal to minimum." << endl;
cin >> b;
} while (a > b || !isdigit(a) || !isdigit(b));
return random(a,b);
}
int main()
{
cout << require() << endl;
}
You should not use isdigit as this relates to a particular character is a digiti. Instead the loop should look like this:
int require() //makes sure a < b and both are digits
{
validNumbers = true;
do
{
cout << "Enter minimum number" << endl;
cin.clear();
cin >> a;
} while (cin.fail());
do
{
cout << "Enter maximum number. Note: Has to be greater or equal to minimum."
<< endl;
cin.clear();
cin >> b;
} while (cin.fail() || a > b);
return random(a,b);
}
PS: You only need to call srand (time(NULL)); once at the start of the program.
You are reading the numbers as, well, numbers not as characters as the isdigit function expects. If you are using a C++11 compliant standard library, the values of a and b will actually be zero if the input is not valid integer numbers, which means that e.g. !isdigit(a) will be true. If you are using a non-C++11 library, then the value of a and b will be random, and will most likely cause !isdigit(a) to be true as well as the amount of valid digit ASCII values in a full 32-bit integer range is quite small.
If you read a reference about the input operator, like this one you will see that if extraction fails, then the streams failbit will be set. This can either be tested "inline" like this:
if (!(std::cin >> a))
{
std::cout << "Not a valid number, try again: ";
continue;
}
Or it can be tested using the streams fail function.

How to properly use cin.peek()

This function is supposed to read a fraction and place it in an array. If the user enters '0' the function is supposed to exit. I am trying to do this using the cin.peek() function but execution always goes into the if statement and doesn't allow the user to exit.
How should I properly code this (I am open to not using peek(), I thought it was the simplest way of doing it.)
Thanks!
void enterFrac(Fraction* fracs[], int& index)
{
int n, d;
char c, slash;
cout << "Enter fractions (end by entering a 0): ";
c = cin.peek();
if ( c != '0')
{
cin >> n >> slash >> d;
Fraction* f = new Fraction();
f->num = n;
f->den = d;
fracs[index] = f;
index++;
}
}
This test of peek() works however:
#include <iostream>
using namespace std;
int main () {
char c;
int n;
char str[256];
cout << "Enter a number or a word: ";
c=cin.peek();
if ( (c >= '0') && (c <= '9') )
{
cin >> n;
cout << "You have entered number " << n << endl;
}
else
{
cin >> str;
cout << " You have entered word " << str << endl;
}
return 0;
}
There are two issues with your use of std::istream::peek():
This function access the next character and does not skip leading whitespace. You probably want to skip leading whitespace before determining what the next character is, e.g., using the manipulator std::ws: (std::cin >> std::ws).peek().
The result from std::istream::peek() is not a char. Instead, it is an std::char_traits<char>::int_type (which is a fancy spelling of int). The result may, e.g., be std::char_traits<char>::eof() and if the value of '0' happens to be negative (I'm not aware of any platform where it is; however, e.g., the funny character from my name 'ΓΌ' is a negative value on platforms where char is signed) you wouldn't get the correct result, either. That is, you normally compare the result of std::istream::peek() against the result of std::char_traits<char>::to_int_type(), i.e., you'd use something like this: std::cin.peek() == std::char_traits<char>::to_int_type('0')
That said, your program doesn't check whether it could successfully read the nominator and the denominator, separated by a slash. You always want to verify that reading was successful, e.g., using something like
if ((std::cin >> nominator >> slash >> denominator) && slash == '/') {
...
}
Just for entertainment, you can create a manipulator for testing that a character is a slash, indeed:
std::istream& slash(std::istream& in) {
if ((in >> std::ws).peek() != std::char_traits<char>::to_int_type('/')) {
in.setstate(std::ios_base::failbit);
}
return in;
}
This way, you'd encapsulate the test for slash. If you need to use this in multiple places this is quite handy.