Condition in while loop using cin - c++

I have following code
//in main
int x;
while ( cin>>x ){
// code goes here
}
Now,i know that this loop executes untill read to x fails which occurs when type mismatch occurs
So pressing a char lets me to come out of loop as x is of type int and char will not be read from input stream.
But problem is with whitespaces, as they are also not int so why loop does not ends when i press enter or whitespace?

According to The C++ Programming Language Special Edition, $21.9 Advice [5]:
Remember that by default >> skips whitespace; §21.3.2.
And in $21.3.2:
Whitespace is defined as the standard
C whitespace (blank, tab, newline, formfeed, and carriage return) by a call to isspace() as defined
in (§20.4.2).

The comment of #jrok provided the answer.
Hence, as long as the input is a white space cin waits for input which may represent the requested type. It stops if an invalid character is in the stream or - after a valid non white space character has been consumed - the character is a white space.
You might read line by line to detect empty input:
std::string line
while(getline(cin, line)) {
// Note: Omitting the case where the line contains spaces, only.
if(line.empty()) {
// No input;
break;
}
else {
// Parse and process the line.
}
}
Note: If skipping white spaces is disabled, the behavior changes.

Related

What exactly empty input means for cin.get()?

I think it's a simple question, but I don't understand the concept in this sample of code, mainly in the while loop:
#include <iostream>
const int ArSize = 10;
void strcount(const char * str);
int main(){
using namespace std;
char input[ArSize];
char next;
cout << "Enter text:\n";
cin.get(input, ArSize);
while(cin){
cin.get(next);
while(next != '\n')
cin.get(next)
strcount(input);
cout << "Enter next line, empty line ends the program:\n";
cin.get(input, ArSize);
}
cout << "The end\n";
return 0;
}
...
What I understand is that the while loop continues until cin returns false. It filters out the remaining input that's left in the buffer (because it wasn't the size of ArSize or under, or it was - then it will just filter out the newline character) until it meets the newline character. Then it counts string's characters (not important in this question), and then, let's say someone just presses enter. cin.get() discards newline character in input. So if someone for example enters an empty line of text in the terminal, it reads it as 'failed' input and cin returns false? Because if someone proceeds to the new line, just by pressing enter, it just leaves the newline character in the buffer, and cin.get() can't get it so it returns false. Or am I wrong?
In short - What exactly happens if you just press enter? cin.get() can't get the input because there's only newline in buffer and it counts it as failed input, so it returns false?
If cin.get(input, ArSize); reads no characters (i.e. the first character it encounters is a newline) it calls setstate(failbit) putting the stream into a failed state and therefore while(cin) becomes false, ending the loop.
As you can see here from the CPP reference https://en.cppreference.com/w/cpp/io/basic_istream/get
cin. get() is used to read the next character from the keyboard buffer and it returns that character in case it was available to be read and returns EOF otherwise and sets failbit and eofbit (which makes the expression in the if statement evaluates to false).
now let's see the code in action line by line:
while(cin){
this evaluates to true as long as the failbit flag in the cin object is set to goodbit showing no error. (https://en.cppreference.com/w/cpp/io/ios_base/iostate)
cin.get(next);
while(next != '\n')
cin.get(next)
the first line reads the next character from the keyboard buffer and stores it in the next variable and the while loop checks for the newline character which is equivalent to pressing Enter if it is not the next character in the buffer then continue reading and storing in next until it meets a newline character then it exits the loop returning to the outer while loop.
strcount(input);
cout << "Enter next line, empty line ends the program:\n";
cin.get(input, ArSize);
then strcount function as I assume is used to count the characters entered by the user in the input array by this line of code before the while loop.
cin.get(input, ArSize);
and then at the last line inside of the while loop, the program reads another input by the user.
Please Note:
the use of these three lines here is to make sure that each line is read at every single loop with no characters read in the second input before the newline character appears even if the number of characters is bigger than the ArSize variable. when that happens the first line before the while loop will read the number of ArSize from the buffer and if there are remaining characters other than the newline it will be read by the three lines until a newline appears so that the next get function will start looking for characters in the buffer after the previous newline.
cin.get(next);
while(next != '\n')
cin.get(next)
if there is anything unclear please let me know.

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

why does this C++ program works for the first line of input but not second or third?

I want to write a program which prints Real Fancy if the given string contains "NOT" or "not" and regularly fancy if it doesn't contain not.
Ex: "this is not a string"
o/p: Real Fancy
"this is nothing"
o/p: regularly fancy
The problem is it prints Real Fancy if my first testcase input is "not is this line". But if the same line is given as input in second or above testcase it is not working and printing regularly fancy.Why? Any help?
Here is the code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;//No.of test cases
cin>>t;
while(t--)
{
string quote;//the input from user
string found="not";//word to be found
string temp="";
int not_found=0;
cin.ignore();
getline(cin,quote);
//Splitting the given line into words and store in a vector
vector<string> words;
istringstream iss(quote);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(words));
//Scan for "not" and if found break from for loop
for(int i=0;i<words.size();i++)
{
temp=words[i];
transform(temp.begin(),temp.end(),temp.begin(),::tolower);
if(temp==found)
{
cout<<"Real Fancy"<<endl;
not_found=1;
break;
}
}
if(not_found==0)
cout<<"regularly fancy"<<endl;
}
return 0;
}
The input pattern looks like
t
quote
quote
quote
...
The reading of t
cin>>t;
stops as soon as it finds an input that cannot possibly be an integer. This includes the newline character representing the end of the line, leaving the newline character in the stream to be consumed later (see Why does std::getline() skip input after a formatted extraction? for more on that problem). The skipping problem has been resolved with a
cin.ignore();
getline(cin,quote);
in the while loop, but that traded one bug for another. If there was no preceding formatted input to leave unwanted characters in the stream, cin.ignore(); will be throwing out the legitimate first character of the input.
This will happen on the second and subsequent reads. The input will wind up looking like
t //newline consumed by ignore
quote //newline consumed by getline. ignore consumes first character of next line
uote //newline consumed by getline. ignore consumes first character of next line
uote //newline consumed by getline. ignore consumes first character of next line
..
Solution:
Move it to after the input that leaves the unwanted character in the stream
cin>>t;
cin.ignore();
A better alternative is to the ignore so that you can make certain you get rid of all potential garbage on the end of the line
cin>>t;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
This will read from the stream up to the maximum possible length of the stream or a newline is found and discarded, whichever comes first.
Always clean up after an operation rather than before the next. It keeps the related code closer together, aiding in readability, and protects you from cases where there is nothing from before to clean up.

Enter character instead int C++

I am writing a code that tally when an integer data type or character is entered.
int numero,
countInteger = 0;
countCharacter = 0;
while ( 1 ) {
try {
cin >> numero;
cout << numero;
throw numero;
} catch (...) {
countCharacter++;
cout << "Error";
}
}
If I entered Integer, counter in "countInteger" (but not show it in the code). If I enter a character, it is aa exception and recorded in "countCharacter".
But when I run the code generates an infinite loop and does not allow me to re-enter again. They could help me please. Guide me, you may have a bad concept.
When you try to read an integer, and you give something that's not an integer as input, there are two things happening: The first is that the stream gets its failbit set, the second things that happens is that the input is not extracted. So next iteration you read the same input again, and again and again...
I suggest another tactic: Read as a character, then see if it is a digit, an alphabetic character, or something else completely. Optionally, if you need the actual full number, read as a string, and try to convert to an integer.
A clarification: Input using std::cin is buffered. When you use the input operator >> then std::cin extracts characters from the buffer. If you try to read a number, but the first character in the buffer is not a digit, then the input operator will fail, and leave the character in the buffer.
Simple (hopefully) example:
Lets say you have this code
int number;
std::cin >> number;
std::cin >> number;
std::cin >> number;
As input for that part of the code, you enter
123abc
The first input will read 123 from the input, and stop at the letter, leaving the input as
abc
Now we come to the second input, and the code will see that the first character is not a digit, so it will set the failbit in the stream and leave the input as is:
abc
Then with the third input, the exact same thing as in the second happen.
Now imagine this was in a loop instead, the input operator >> will iteration after iteration see the non-digit input an promptly return, effectively giving you an infinite loop.
Now for a clarification of my suggestion... Depending on the goals and requirements of the program, you can instead read into a character and use the character classification functions to see what types you have.
Something like
int countDigit = 0;
int countCharacter = 0;
char ch;
while (std::cin >> ch)
{
if (std::isdigit(ch))
++countDigit;
else if (std::isalpha(ch))
++countCharacter;
else
{
// Not a digit or an alphabetic character
// I.e. newlines, spaces, control characters, etc.
}
}
Finally a note about using exceptions for this: Most people would consider it bad. Exceptions are for exceptions, exceptional cases, not as part of the normal flow of the program. Throwing an exception is expensive and disrupts the normal flow. Only use them for exceptional things, like errors.

cin.getline(char, int) gets skipped when in a loop

This is the code I have been trying to execute on TurboC++ 3.0 (Yes, I know it's ancient but can't help it), when the program goes into the loop, it skips the value of y every time including the first attempt. Any help would be appreciated but please avoid rubbing salt into wounds by asking why TurboC++ 3.0. Thanks in advance.
void main()
{
int x, z;
char y[10];
for (int i=0;i<5;i++)
{
cout<<"\nX:";
cin >> x;
cout<<"\nY:";
cin.getline(y,10);
cout<<"\nZ:";
cin>>z;
}
for(i=0;i<5;i++)
{
cout<<x<<"\n";
cout.write(y, 10)<<"\n";
cout<<z<<"\n\n";
}
}
and even if I use cin.get(var) where var is a character, i still get weird results like a heart, diamond or even a smiley.
You get weird results because you are not terminating your c style string with a null character.('\0').
The problem you are facing is because , fail bit or eof bit is set. To remove that, do the following:-
You can use
cin.clear() ;
to clear if any error bits are set and then use
cin.ignore(100, '\n') ;
// 100 is just a random no, change it depending on your size of input.
to ignore any irrelevant characters int the stream.
or you can do the following:-
after cin>>x just type cin.ignore(), it will flush out any newline characters present in the buffer .
it skips the value of y
cin >> x reads the input until it finds something that's not a digit - in this case, the end-of-line character. That character is left in the stream.
getline reads the input until it finds an end-of-line character (or the end of the stream). Since you've left one in the stream, it finds it straight away and doesn't read anything.
You can call cin.ignore(-1,'\n') to ignore the remainder of the first line after reading x (assuming your prehistoric library behaves like the modern one).
i still get weird results like a heart, diamond or even a smiley
cout.write(y, 10) is wrong - there are up to 9 valid characters in y, followed by the null terminator. You want cout << y to treat it as a null-terminated string and print only the valid characters.