cout << "Enter a positive integer or zero: ";
getline(cin, streamStr);
stringstream(streamStr) >> number;
if (!number) {
cout << "invalid input detected or the input is too big.\n";
return 1;
}
inputs like "%234" or "sdf2334" always fall to 0 , which is false in bool expression, but 0 is still a number.
How to check if the input is really invalid like "%234"??
You need to check the returned value of the operator>>, which is not the same as the value of the variable you're reading into:
if (stringstream(streamStr) >> number) {
...
So what's the returned value, then? If you check the docs, you'll see it's a stream itself. It goes to the operator bool of it (because it's used in an if statement), which in turn returns the validity of the stream, or, IOW, if the last operation succeeded.
If you want to ensure the stream doesn't contain anything besides the number use
if (sstream.rdbuf()->in_avail() > 0) {
// something is still there
And to skip whitespace at the end if you want to allow it:
sstream >> std::ws;
So, all in all...
template<typename T,
// those are optional
enable_if<is_default_constructible<T>::value>::type,
enable_if<is_input_streamable<T>::value>::type
>
optional<T> myRead(string input, bool allowTrailingWs = true) {
stringstream str(input);
T val;
// check parsing
if (!(str >> val))
return none;
// allow whitespace at the end
if (allowTrailingWs)
str >> std::ws;
// check if there's any garbage left
if (str.rdbuf()->in_avail() > 0)
return none;
return val;
}
The code above is just for illustration purposes. Shall you need more advanced parsing, check out Boost.Spirit.
Also, apparently this isn't guaranteed to work every time. Using:
auto inputEnd = ss.tellg();
ss.seekg(0, std::ios::end);
if (inputEnd == ss.tellg()) {
To check if the ss is empty could help fix that.
I don't think you understand how streams work. Allow me to address your misconception:
The stream won't attempt to extract any value into number if the data being evaluated doesn't correspond to formatting requirements of the type. Extraction works by the stream iterating through each character in the character sequence one by one, and testing each character as a viable datum for the type to which the extraction is targeted. If the character is not viable, extraction stops (this is why you are seeing success upon entering something like "2342fdsf"; the stream will keep extracting until it finds an invalid character. "2342" are valid characters for an integer while "f" is not)
If the stream finds an invalid character, nothing further is done to the variable (in this case number). In fact, it is implementation-defined what value an uninitialized variable has if extraction failed to produce any characters. With that in mind, it is potentially dangerous to check the value of the operand to determine if I/O failed. This is where checking the stream state comes in:
std::istringstream iss(streamStr);
if (iss >> number)
{
std::cout << "Extraction produced: " << number << '\n';
}
If the extractions fails, the stream will set the appropriate bits. The stream will then be implicitly converted to a boolean using operator bool() (or operator void*() pre-C++11 where it will subsequently undergo conversion to boolean). The boolean function will check the stream state using !this->fail() (which checks both badbit and failbit) and if the function returns true, the if body will be executed.
If the stream is not in a good state (!this->fail() returns false), that means the extraction failed to produce a value and the if statement body goes unevaluated.
By encasing the extraction in a conditional check, not the value of the thing you tried to extract into.
Assuming number must be a char value, try using the cctype library which is helpful for dealing with strings. It has functions such as
isdigit(Char_Exp) //Returns true if the value is a digit
and
isctrl(Char_Exp) //Returns true if the value is a control character like %(modulus)
Here is a link to a C++ cctype library reference: cctype library reference
To test number I would advise you create a function of type Boolean and so that it tests all possible input errors at once.
Related
I have a problem that cin.ignore() can not remove input from the buffer.
#include <iostream>
#include <string>
int main() {
using namespace std;
int x=0;
string k;
cin >> x;
cin.ignore(100,'\n');
cin.clear();
cin >> k;
cout << k << endl;
}
For the above code:
input : abc (program ends when I just input abc)
output : abc
I was really surprised because cin.ignore() did not remove "abc" from the input buffer.
What is wrong with my code?
If I change the positions of cin.ignore() and cin.clear(), it works well, why is that?
This code:
int x=0;
cin >> x;
Causes cin to be put into an error state (specifically, the failbit flag is set) if the input is not convertible to an int.
Per cppreference.com:
std::basic_istream<CharT,Traits>::operator>>:
This function behaves as a FormattedInputFunction. After constructing and checking the sentry object, which may skip leading whitespace, extracts an integer value by calling std::num_get::get().
...
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
(until C++11)
If extraction fails, zero is written to value and failbit is set. For signed integers, if extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() (respectively) is written and failbit flag is set. For unsigned integers, if extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() is written and failbit flag is set.
(since C++11)
...
Thus, any further I/O operations on the stream are disabled, like ignore(), until you clear() the error state to re-enable I/O.
std::basic_ios<CharT,Traits>::clear:
Sets the stream error state flags by assigning them the value of state. By default, assigns std::ios_base::goodbit which has the effect of clearing all error state flags.
std::basic_istream<CharT,Traits>::ignore:
ignore behaves as an UnformattedInputFunction. After constructing and checking the sentry object, it extracts characters from the stream and discards them until any of the following conditions occurs:
...
C++ named requirements: UnformattedInputFunction:
An UnformattedInputFunction is a stream input function that performs the following:
Constructs an object of type basic_istream::sentry with automatic storage duration and with the noskipws argument set to true, which performs the following
if eofbit or badbit are set on the input stream, sets the failbit as well, and if exceptions on failbit are enabled in this input stream's exception mask, throws ios_base::failure.
flushes the tie()'d output stream, if applicable
Checks the status of the sentry by calling sentry::operator bool(), which is equivalent to basic_ios::good.
If the sentry returned false or sentry's constructor threw an exception:
sets the number of extracted characters (gcount) in the input stream to zero
if the function was called to write to an array of CharT, writes CharT() (the null character) to the first location of the array
...
cin.clear(); removes the error flag from cin
and cin.ignore(); ignores the next numbers of spaces.
Since you declared x as a Integer and you write it in first, the console expects that an integer to be read first. if you type abc at first instead you are typing in a string and the console returns an error flag because it expects an integer. That's why your program ends right after that.
If you put cin.clear(); right after cin>>x and type abc the error flag that is been thrown will be ignored and the console continues with cin>>k
Currently I'm self-learning C++ Primer 5th. Here comes something I'm not sure. (I couldn't find the exact relevant question on F.A.Q).
Consider this while loop:
while(std::cin>>value){...} \\value here was defined as int.
The text book says:
That expression reads the next number from the standard input and stores that number in value. The input operator (§ 1.2, p. 8) returns its left operand, which in this case is std::cin. This condition, therefore, tests std::cin.When we use an istream as a condition, the effect is to test the state of the stream. If the stream is valid—that is, if the stream hasn’t encountered an error—then the test succeeds.
My question is: does std::cin read input into value first then test the validation of std::cin, or test std::cin first then decide whether to read into 'value'? I'm quite confused about when it "returns its left operand".
Remember that your code is equivalent to:
while (std::cin.operator>>(value)) { }
Or:
while (1) {
std::cin >> value ;
if (!std::cin) break ;
}
The "code" always tries to read from std::cin into value before testing std::cin.
Let's look at the quote:
[...] The input operator (§ 1.2, p. 8) returns its left operand, which in this case is std::cin. [...]
This only means that std::cin.operator>>(value) return std::cin.
This condition, therefore, tests std::cin. When we use an istream as a condition, the effect is to test the state of the stream. If the stream is valid—that is, if the stream hasn’t encountered an error—then the test succeeds.
What the text book says is that after trying to read an integer from std::cin to value, the >> operator returns std::cin. If std::cin is in a good state after reading value, then the test passes, otherwize it fails.
Some extra details:
When you do std::cin >> value, you basically call istream::operator>>(int&), and yes there is a test inside that method: If the test passes, then the internal state of std::cin is set to ios_base::goodbit, if it fails, internal state is set to on of the error flag (eofbit, failbit or badbit).
Depending on the exception mask for std::cin, if the internal test fails, an exception may be thrown.
From your quote:
When we use an istream as a condition, the effect is to test the state of the stream.
This basically mean that:
if (std::cin) { }
Is equivalent to:
if (!std::cin.fail()) { }
And std::cin.fail() check for failbit or badbit. This means that while (std::cin >> value) { } does not test the eofbit flag and will only fail when the input cannot be converted to an integer value.
does std::cin read input into value first then test the validation of
std::cin, or test std::cin first then decide whether to read into
'value'
cin first tries to read an int from the standard input, if cin is in a good state: if it fails to, it will set the stream to a bad state; regardless of the operation done, it will return the stream itself (i.e. the "left operand" -- cin), that will allow you to check for success or failure.
If you wanted to explicitly test the validity of the stream first and only then try to read the value, you would have:
while (cin && cin >> value)
but it's pretty redundant, since, as I've told you, cin will not even try to read value if it's already in a bad state.
There are two tests.
The first test is the condition of the while statement
while(std::cin>>value){...}
This condition tests the result of calling operator function operator >>
The second test is a condition within the operator. If the state of the stream std::cin is good then the function tries to read an integer from the string. Otherwise it returns std::cin with the current erroneous state of std::cin.
In the while condition there is an expression
std::cin>>value
This expression must be evaluated. So this condition tests the result of the call of operator >> .
The result of the operator is the stream std::cin But it can be contextually converted to a bool value due to operator
explicit operator bool() const;
which returns the state of the stream
!fail().
I assume your "value" is for example an int
The stream tries to read input until the next whitespace.
if eof is found ... -> then the state will be set to "eof", >> will return the stream and the boolean evaluation of the stream will return false
if an error (I/O for example) happens during the reading process, the state will be set to "bad", >> will return the stream and the boolean evaluation of the stream will return false
if whitespace has been found, then a conversion from the read characters to int (the above assumption) will be attempted. If it fails (because the read input is for example: "xx" and not a number) the state of the stream will be set to "fail". >> will return the stream and the boolean evaluation of the stream will return false
if we are so far down the chain, eof was not found, no IO error (or other) happened, and the characters -> int conversion was successful. >> will return the stream and the boolean evaluation of the stream will return true.
And your "value" will contain the appropriate value
Presumably you wouldn't have any confusion with a simple function call:
SomeReturnType some_function(int&);
while (some_function(value)) { ... }
The above code will repeatedly call some_function until the return value from the function call, interpreted as a boolean, is false. The function is called for each step in the loop. Whether the function changes the value of value is up to the function. It certainly can do so, and presumably will do so (but that's an issue for the designer of the function).
The loop while (std::cin>>value) {...} is completely equivalent to while (std::cin.operator>>(value)) {...}. This is just a function call to the member function std::stream::operator>>(int&).
The operator first reads the value and then returns a reference to the object. The while statement first calls that operator and second tests the returned value.
I am learning C++ and I'm in doubt on how the following code works. My aim is to accept numbers (as a std::string) from the Command Line separated by spaces and separate these numbers from the string. I posted another question related to this and got the program working using the code below. Can you please explain to me how the numbers are actually extracted from the strings?
string gradesFullLine;
getline(cin, gradesFullLine);
stringstream gradeStream(gradesFullLine);
for(gradeStream >> grade; gradeStream; gradeStream >> grade) {
grades.push_back(grade);
}
Here's a simpler way to write the loop:
while(gradeStream >> grade) {
grades.push_back(grade);
}
Here's how it works:
gradeStream >> grade invokes operator>>(std::istream, int) (or whatever numeric type grade is). This attempts to "extract" a number from the stream, and updates the "stream state" indicating success or failure.
The result of the expression gradeStream >> grade, i.e. the return value of operator>>(std::istream, int), is gradeStream itself.
Any standard stream has a method equivalent to operator bool() const which lets you use the stream in a boolean context, such as an if() or while() condition. This operator returns true if the stream is "good" meaning it has not had any I/O errors (including reading past the end of the stream).
So the boolean value is used as the while condition, meaning that the loop will be entered so long as gradeStream has a "good state" which means grade has been populated with a number extracted from the stream (how this extraction happens is defined by your particular system implementation).
I was trying to verify if the entered value was an integer with the type id function. I know that the returned value would be i and not integer. I don't know why any entered value returns false and the programs stops. Any help would be appreciated.
The program works fine without the while statement
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int number, factorial;
cout << "Enter a number: ";
cin >> number;
factorial = 1;
while (typeid(number).name() == "i") {
for (int i = number; i >= 1; --i){
factorial *= i;
}
cout << factorial;
}
}
The returned string of the member function name of std::type_info is implementation defined. It's not guaranteed to be "i". If you want to check the type of an object against another type you should do:
typeid(object) == typeid(T)
for any T type. In your example:
typeid(number) == typeid(int)
But the above comparison will always return true because number is declared as int. typeid is usually helpful to inspect the dynamic type of a polymorphic object. In your case number is not polymorphic at all. Therefore you don't need it.
What you seem to be worried about is validation of the input. For that you should consider that if operator>> of std::cin fails the following will happen:
(until C++11)
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
(since C++11)
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() is written and failbit flag is set.
Therefore all you need to do is check the fail bit right after requiring it:
std::cin >> number;
if (std::cin) {
// ...
}
When streams read to an object, they check the format that's being read and parse that format into the object. If the stream cannot correctly parse that data, it sets an error in its error mask. The error mask is used to determine if an I/O operation succeeded or failed. When a stream is put into a boolean context (like in the parameters of an if() or while() loop), it will return true if its error mask is free of any errors.
If your intention is to only use an integer, then I suggest you adopt the pattern of using the stream itself to check if I/O operations succeeded. For example, this is how it will look in your code:
if (std::cin >> number) {
...
}
The formatted extractor operator>>() returns a reference to the stream which will then call its member function explicit operator bool() const to access its stream state and return true or false depending on whether the stream successfully read the contents of the stream into number.
I am given a list of words in a text file, all seperated by newlines. Reading them using fstream and >>, and not knowing the amount of words there are. How do I tell the program when to stop? I've tested it out, and the value of the variable just stays the same of the last word read.
Checking the state of the stream after extraction is always a good idea. It tells you if there were any problems while performing the extraction, or whether the file stream has reached the end-of-file character (EOF).
The latter case is what you're dealing with. All you need to do is perform the extraction while the stream is in a good state, which is idiomatically done in the following way:
while (in >> str) {
// ...
}
After the stream performs the extraction, operator bool() is invoked, which calls !fail(). Using a while loop will allow the next extraction to be performed automatically. It will stop when the stream has performed an incorrect extraction, is perhaps out of memory, when it hits the EOF character, or some other user-defined situation.
You've failed the fundamental principle of I/O: You must check whether your input operation succeeds. You cannot know that in advance, you only learn that after you have tried:
for (std::string word; std::cin >> word; )
// ^^^^^^^^^^^^^^^^<----------- test for success
{
std::cout << "Here is one word: " << word << std::endl;
}
You have to remember that the input operator >> returns the stream it uses, and that streams can be used as boolean conditions. That means you can use it as a loop condition:
while (some_stream >> some_variable)
{
...
}