Unexpected stringstream behavior - c++

Consider the following code:
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
stringstream ss;
ss << string("12");
int h;
ss >> h;
cout << h << endl;
ss.str(string("")); // clear the content of ss
ss << string("30");
int m;
ss >> m;
cout << m << endl;
return 0;
}
Running the above code yields some random output:
12
0
At some other times, the following output is observed:
12
4
I expected the output to be simply:
12
30
Why did I get the unexpected results?
Also, what should be the best way to parse a string s to int i without necessary C++11 support? Should it be int i = atoi(s.c_str())?

When you extract 12 from the stream, you reach the end of it, which puts it in a bad state. Any further extractions will fail. You need to call ss.clear() around the time you clear its contents.
If you had checked the success of your extractions, you would have avoided this problem. I generally expect to see any extraction from a stream as some kind of condition.
And yes, using string streams to parse strings as integers is a perfectly reasonable way to do it pre-C++11. I would prefer it over using atoi. For anybody who wants to know the C++11 way, use std::stoi.

For those who're here with something similar to the above but not exactly, I found that when you've got a stream in a scenario where you need to re-use it (like in a while loop), the easiest way to avoid head-aches (in addition to ss.clear) is to create a new stream each time. For example:
int GetInteger(){
cout << "Enter an int: " << endl;
string userInput;
while (true){
stringstream ss;
getline(cin,userInput);
ss << userInput;
//Making sure that an int was passed
int result;
if (ss >> result){
//Making sure that there is no extra stuff after
string extra;
if (ss >> extra){
cout << "Unexpected stuff at end of input: " << extra << endl;
} else{
return result;
}
} else {
cout << "Number you entered is not an INT. Please enter an integer" << endl;
}
cout << "Retry: " << endl;
// ss.clear();
}
}
So every time the user enters an invalid input, at the start of the while loop, I create a new stringstream object. While researching my function's undefined behavior, I found this question that has a similar example.

Related

Any advantages of converting string variable to int using stoi?

What's the benefit of converting the variable from string to int using std::stoi?
I saw a lecture and it declares string variable and converts it to int later. Any reason for doing this? or it's just a preference?
I don't think using stoi in the given code is necessary.
#include <iostream>
int main() {
std::string sAge = "0";
int nGrade = 0;
std::cout << "Enter age: ";
getline (std::cin, sAge);
int nAge = std::stoi(sAge);
if ((nAge >= 1) && (nAge <= 18)) {
std::cout << "Important Birthday" << std::endl;
}
else if ((nAge == 21) || (nAge == 50)) {
std::cout << "Important Birthday" << std::endl;
}
else if (nAge >= 65) {
std::cout << "Important Birthday" << std::endl;
}
else {
std::cout << "Not an important Birthday" << std::endl;
}
return 0; }
There are a couple of reasons people use getline, then convert the string to an int with std::stoi instead of extracting an int directly from the stream (like std::cin >> nAge;).
The first is that it can be a little bit easier to recover from errors this way. If you try to extract an int directly from the stream, but the user enters six instead of 6, the stream will go into a failed state, and you'll need to extract the six from the stream and reset the stream before you can try again.
If you read a line, then use stoi to do the conversion, it's fairly easy to just read a line repeatedly until you get something can convert successfully.
It can also be somewhat clumsy if you try to mix reading things a line at a time with reading things an item at a time. For example:
std::cout << "Please enter your age: ";
std::cin >> age;
std::cout << "Please enter your name: ";
std::getline(std::cin, name);
Assuming the user enters data roughly as intended, we can expect this to read the name as an empty string. The problem is that when we read the age, it read the digits and converted them to age. But that was followed by a new-line character, which hasn't been read yet--so when we call getline, it will see the new-line, and treat that as the end of the line, so name ends up empty. There are ways to avoid/fix this but they add a bit of clumsiness, so sometimes it's easier to just read all the data with getline, and convert it as needed afterwards.

What do you do in C++ if you ask for an integer and the user inputs "b"?

I'm new to statically typed C++. In JavaScript, I could just check the data type first, but that seems to be very complicated, and the answers all seem to imply that you aren't "getting" the language.
here's the code I was testing out rand() with, where I came upon the issue of converting strings to integers:
int main(){
std::string input;
cout <<endl<< "What to do?"<<endl;
cin >> input;
if (input == "rand")
{
cout << "what is the max?" << endl;
cin >> input;
int number;
if (stoi(input) > 1) {
number = stoi(input);
}
else {
number = 10;
cout << "using 10"<<endl;
}
cout << rand() % stoi(input);
return main();
}
}
so in Javascript, I would just check the type of input or result, but what do people do in C++?
Not allowed to say thank you in the comments so I'm saying thank you here!
Well, let's try out what happens: https://godbolt.org/z/1zahbW
As you can see, std::stoi throws an exception if you pass it invalid input or its input is out of range.
You should, however, be aware that std::cin >> some_string; is somewhat non-obvious in that it reads in the first "word", not a line or anything like that, and that std::stoi does the same thing (again).
One way to perform the check, could be like this:
#include <string>
#include <iostream>
int main(){
std::cout << "Please give me a number: " << std::flush;
std::string input;
std::getline(std::cin, input);
try {
auto value = std::stoi(input);
std::cout << "Thanks for the " << value << " (but the string was \"" << input << "\")\n";
} catch(std::invalid_argument const&) {
std::cout << "The provided value is not an integer\n";
} catch(std::out_of_range const&) {
std::cout << "The provided value is out of range\n";
}
}
https://godbolt.org/z/rKrv8G
Note that this will parse " 42 xyz" as 42. If that is a problem for your use case, you may wish to use std::strtoi directly, or to check if your input is valid before parsing (e.g., using a regex)
Regarding to the documentation of std::stoi it throws an std::invalid_argument.
What you could do is to place your std::stoi call inside a try and then catch the std::invalid_argument, but personally i wouldn't do that.
Instead, it is (most likely) a lot better to check if the first character of your input is an int, because if it is one, it can simply be parsed by std::stoi.
You can do that by e.g. doing the following:
int max = 0;
std::string input;
std::cin >> input;
if(std::isdigit(input[0]))
max = std::stoi(input);
EDIT: Please note that this would not respect the case of a too big number, to handle that case you would need an additional check.

Why does this cause in infinite loop with chars but not doubles?

I feel like im doing something really silly wrong. I just want the program to tell the user when they are entering non-doubles, and continue to loop back to the cin where you enter a value.
I want the user to input any number. Then essential do this trivial math and repeat. Its working fine in that regard, the problem comes when some unexpected input like a char gets entered. Then the input somehow sends it into a loop where it loops the math problem, instead of just telling the user that they must type a number and looping back to cin type in a new number.
#include <iostream>
#include <cstdlib>
using std::cout; using std::cin; using std::endl;
long double domath(long double i)
{
cout << i << "/" << 2 << "=" << i/2 << endl;
cout << i/2 << "*" << 10 << "=" << (i/2)*10 << endl << endl;
cout << 5 << "*" << i << "=" << 5*i << "\n\n";
return 0;
}
int main()
{
long double in = 0;
while(true)
{
cin >> in;
if (cin.fail()) {
in = char(int(in));
}
domath(in);
}
system("pause>nul");
return 0;
}
You don't clear the cin in case of fail, and it infinitely tries to parse wrong input to double, failing every time. You need to clear the buffer in case of error:
if (cin.fail()) {
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
in = char(int(in));
}
Also, can't understand what you're trying to achieve with
in = char(int(in));
in is a long double variable and will hold the last value you assigned to it, no need to "convert" it to do math.
Couldn't you try doing something like this?
int x;
if(std::cin >> x)
doSomethingCool(x);
else
std::cout << "Error, not a valid integer!" << std::endl;
Exit your loop on bad input.
I think this just feels more natural/looks cleaner than clearing the buffer and all the other jazz. Just my opinion.
if (cin >> x) - Why can you use that condition?
edit: Bul's answer is still a good one though.

Converting string to number when using getline()

I've picked up a book on C++ and I'm basically at the very beginning of it (just started). For some of the problems I had to solve within the book I used the input stream cin the following way -->
cin >> insterVariableNameHere;
But then I did some research and found out the cin can cause a lot of problems, and so found out about the function getline() within the header file sstream.
I'm just having some trouble trying to wrap my head around what's happening in the following code. I don't see anything that uses the extraction operator (>>) to store the number value in. Its (my problem) further explained in the comments I left.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
// Program that allows a user to change the value stored in an element in an array
int main()
{
string input = "";
const int ARRAY_LENGTH = 5;
int MyNumbers[ARRAY_LENGTH] = { 0 };
// WHERE THE CONFUSION STARTS
cout << "Enter index of the element to be changed: ";
int nElementIndex = 0;
while (true) {
getline(cin, input); // Okay so here its extracting data from the input stream cin and storing it in input
stringstream myStream(input); // I have no idea whats happening here, probably where it converts string to number
if (myStream >> nElementIndex) // In no preceding line does it actually extract anything from input and store it in nElementIndex ?
break; // Stops the loop
cout << "Invalid number, try again" << endl;
}
// WHERE THE CONFUSION ENDS
cout << "Enter new value for element " << nElementIndex + 1 << " at index " << nElementIndex << ":";
cin >> MyNumbers[nElementIndex];
cout << "\nThe new value for element " << nElementIndex + 1 << " is " << MyNumbers[nElementIndex] << "\n";
cin.get();
return 0;
}
stringstream myStream(input): Creates a new stream that uses the string in input as "input stream" so to speak.
if(myStream >> nElementIndex) {...): Extracts number from the stringstream created using the line above into nElementIndex and executes ... because the expression returns myStream, which should be non-zero.
You were probably confused by using the extraction as the condition in the if statement. The above should be equivalent to:
myStream>>nElementIndex; // extract nElement Index from myStream
if(myStream)
{
....
}
What you probably wanted was
myStream>>nElementIndex; // extract nElement Index from myStream
if(nElementIndex)
{
....
}

How to make cin >> not convert float to integer?

I have the following simple code:
#include <iostream>
int main()
{
int a;
std::cout << "enter integer a" << std::endl;
std::cin >> a ;
if (std::cin.fail())
{
std::cin.clear();
std::cout << "input is not integer, re-enter please" <<std::endl;
std::cin >>a;
std::cout << "a inside if is: " << a <<std::endl;
}
std::cout << "a is " << a <<std::endl;
std::cin.get();
return 0;
}
When I run the above code and input: 1.5, it outputs: a is 1. FYI: I compile and run the code with gcc 4.5.3.
This means that if cin expects an integer but sees a float, it will do the conversion implicitly. So does this mean that when cin sees a float number, it is not in fail() state? Why this is the case? Is it because C++ does implicit conversion on >> operator?
I also tried the following code to decide whether a given input number is integer following idea from this post: testing if given number is integer:
#include <iostream>
bool integer(float k)
{
if( k == (int) k) return true;
return false;
}
int main()
{
int a;
std::cout << "enter integer a"<< std::endl;
std::cin >> a ;
if (!integer(a))
{
std::cout << "input is not integer, re-enter please" ;
std::cin.clear();
std::cin >> a;
std::cout << "a inside if is: " << a <<std::endl;
}
std::cout << "a is " << a <<std::endl;
std::cin.get();
return 0;
}
This block of code was also not able to test whether a is integer since it simply skip the if block when I run it with float input.
So why this is the case when getting user input with cin? What if sometimes I want the input to be 189, but typed 18.9 by accident, it will result in 18 in this case, which is bad. So does this mean using cin to get user input integers is not a good idea?
thank you.
When you read an integer and you give it an input of 1.5, what it sees is the integer 1, and it stops at the period since that isn't part of the integer. The ".5" is still in the input. This is the reason that you only get the integer part and it is also the reason why it doesn't seem to wait for input the second time.
To get around this, you could read a float instead of an integer so it reads the whole value, or you could check to see if there is anything else remaining on the line after reading the integer.
When reading user input I prefer not to use operator>> as user input is usally line based and prone to errors. I find it best to read a line at a time and validate:
std::string line;
std::getline(std::cin, line);
This also makes it easy to check for different types of numbers.
std::stirngstream linestream(line);
int val;
char c;
if ((linestream >> val) && !(linestream >> c))
{
// Get in here if an integer was read.
// And there is no following (non white space) characters.
// i.e. If the user only types in an integer.
//
// If the user typed any other character after the integer (like .5)
// then this will fail.
}
Of course boost already supports this:
val = boost::lexical_cast<int>(linestream); // Will throw if linestream does
// not contain an integer or
// contains anything in addition
// to the integer.
Boost of course will convert floats as well.
I have some snippet which is kind a poor coding, but it works.
This method is pretty simple, but doesn't handle case when input value is invalid.
See more: https://en.cppreference.com/w/cpp/string/byte/atof
static float InputFloat(std::string label)
{
std::string input;
std::cout << label;
std::cin >> input;
return atof(input.c_str());
}
int main()
{
float value = InputFloat("Enter some float value: ");
std::cout << "value = " << value;
return 0;
}