Why does stringstream >> change value of target on failure?
From this reference:
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. If extraction results in the value too large or too small to fit in value, std::numeric_limits::max() or std::numeric_limits::min() is written and failbit flag is set. (since C++11)
It seems that your compiler is compiling in C++11 mode, which changes the behavior.
The input operator uses the locale facet std::num_get
whose get
function invokes do_get
. For C++11 it's specified to use std::strtoll
et. al. type of functions. Before C++11 it apparently used std::scanf
style parsing (going by the reference, I don't have access to the C++03 specification) to extract the numbers. The change in behavior is due to this change in parsing the input.
c++ stringstream not working properly when changing integer to string
std::ostringstream::str()
(1) string str() const;
(2) void str (const string& s);The first form (1) returns a string object with a copy of the current contents of the stream.
The second form (2) sets s as the contents of the stream, discarding any previous contents.
To clean up the buffer, use the second overload as well:
xString = ssObject.str();
ssObject.str("");
// ^^
What's the point of stringstream?
Well, one problem is that you cannot "concatenate a bunch of variables in a string using the + operator" (only other strings or char*s).
So, how are you going to turn all your objects into strings? Unlike Java, C++ does not have any to_string() member convention. On the other hand, every class interested in using iostream will define stream inserters (std::ostream& operator<<(std::ostream& os, const MyClass& foo)
and maybe std::istream& operator>>(std::istream& os, MyClass& foo)
.)
So, you use the stream inserters to convert objects to text. Sometimes you don't want to write to the console or to a file, but instead you want to store it as a string.
Also, using the iostream framework lets you use the manipulators to control precision, width, numerical base, and so on, instead of trying to do all that manually as you construct a string.
Now, that's not to say that the stringstream solution is ideal: in fact, a lot of libraries exist to do the same sort of task better (including at least Boost.Format, Boost.Convert, Boost.Lexical_Cast, and Boost.Spirit just in Boost.)
Why does cin, expecting an int, change the corresponding int variable to zero in case of invalid input?
The behavior you want to observe changed in 2011. Until then:
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
But since C++11:
If extraction fails, zero is written to value and failbit is set. [...]
(From cppr.)
C++ cin reading string into int type returns 0
Not sure why the question got down/close votes as it's clearly stated and not broad (and judging by the comments, many people don't know the answer)...
Anyway, for the code:
int age;
cin >> age;
if the input stream did not contain any digits, then the stream is put into a fail state and age
is set to 0
. The characters in the input stream remain there; they can be read by a future read operation once the fail state is cleared.
The behaviour of operator>>
is summarized on cppreference , the full description in the standard is somewhat complicated.
Note: This changed in C++11; commentors reporting garbage output are either running compilers in pre-C++11 mode, or bugged ones.
Why does filtering out ASCII value 32 (' ') from a stringstream with the following function also filter out '\n' and '\t'?
In this code:
while (ss >> c) {
if (c == ' ') {
The if
will NEVER evaluate as true
, because operator>>
skips leading whitespace by default, which includes spaces, tabs, and line breaks. So c
will never be a whitespace character like ' '
.
Either:
- use
std::noskipws
, like @WhozCraig suggested in comments:
while (ss >> std::noskipws >> c)
- use
std::istream::get()
, which does not skip whitespace:
while (ss.get(c))
That being said, there are other bugs in you code.
You are returning the unmodified s
instead of the prepared final_string
.
It looks like your inner while
loop is trying to minimize runs of 2+ spaces into 1 space for output. Which is fine, except that is losing the character that ends a detected run.
Try something more like this:
std::string filter(const std::string &s) {
std::istringstream iss(s);
char c;
std::string final_string;
while (iss.get(c)) {
if (c == ' ') {
while (iss.get(c)) {
if (c != ' ') {
final_string += ' ';
final_string += c;
break;
}
}
}
else {
final_string += c;
}
}
return final_string;
}
Lastly, when building up a new std::string
in this manner, it is generally more efficient to use an std::ostringstream
instead of operator+=
(unless you reserve()
the std::string
up front), eg:
std::string filter(const std::string &s) {
std::istringstream iss(s);
char c;
std::ostringstream final_string;
while (iss.get(c)) {
if (c == ' ') {
while (iss.get(c)) {
if (c != ' ') {
final_string << ' ' << c;
break;
}
}
}
else {
final_string << c;
}
}
return final_string.str();
}
std::istream to unsigned numerical value, how to detect negative values?
Streams are allowed to take in negative numbers for unsigned types. It has the same mechanics as
unsigned type foo = -some_value
Since they can take in a negative number the stream will never fail and you will have the normal behavior of assigning a negative number to an unsigned type.
We can add a check for this though in your function. For a type T
, T() - T(1) < 0
, will only be true if the type is signed, otherwise the subtraction would wrap around and become the largest value T
can represent. So, if we check that condition, and the string starts with a '-'
, then you know it is not a "valid" value. That makes you function look like
template<typename T>
void checkValid( const std::string& val )
{
std::stringstream str1;
T temp1;
str1 << val;
str1 >> temp1;
if ( str1.fail() || str1.bad() || (!(T() - T(1) < T()) && val[0] == '-') )
std::cout << "error, " << val << " is not a valid string value" << std::endl;
else
std::cout << "ok, " << val << " is converted to " << temp1 << std::endl;
}
If your string can have leading whitespace then you will want to replace the val[0] == '-'
check with something like val[val.find_first_not_of(" ")] == '-'
How do you get the remaining string after a string extracted from a sstream variable?
You can use std::getline
to get the rest of the string from the stream:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
stringstream ss("abc gg rrr ff");
string s1, s2;
ss >> s1;
getline(ss, s2); //get rest of the string!
cout << s1 << endl;
cout << s2 << endl;
return 0;
}
Output:
abc
gg rrr ff
Demo : http://www.ideone.com/R4kfV
There is an overloaded std::getline
function in which a third parameter takes a delimiter upto which you can read the string. See the documentation of std::getline
:
- std::getline
Related Topics
Difference Between Angle Bracket ≪ ≫ and Double Quotes " " While Including Header Files in C++
Is Stateful Metaprogramming Ill-Formed (Yet)
Is There Any Overhead to Declaring a Variable Within a Loop - C++
What How to Use Instead of the Arrow Operator, '-≫'
Is the Safe-Bool Idiom Obsolete in C++11
When Are Static C++ Class Members Initialized
Read Numeric Data from a Text File in C++
"Downcasting" Unique_Ptr≪Base≫ to Unique_Ptr≪Derived≫
Combining Several Static Libraries into One Using Cmake
What Requirements Must Std::Map Key Classes Meet to Be Valid Keys
How to Detect If I'M Compiling Code With a Particular Visual Studio Version
Differences Between C++ String == and Compare()
How to Avoid Memory Leaks When Using a Vector of Pointers to Dynamically Allocated Objects in C++
"Incomplete Type" in Class Which Has a Member of the Same Type of the Class Itself