Issue with Cin When Spaces Are Inputted, Using String Class

Issue with cin when spaces are inputted, using string class

Here's what's happening with the input buffer when you run your program:

std::cin >> name;

You're waiting for input. When you enter "Ryan Cleary", and press enter, the input buffer contains:

Ryan Cleary\n

Now your cin reads input as normal, stopping at whitespace, leaving your buffer like this:

 Cleary\n

Note the beginning space, as it stops after reading Ryan. Your first variable now contains Ryan. If, however, you want the full name, use std::getline. It will read until a newline, not just whitespace. Anyway, continuing on:

std::cin >> age;

Now you're getting another input. There's already something there, though. It skips the whitespace until it can start reading, leaving the buffer with just:

\n

Your second variable gets the text Cleary. Note the newline still in the buffer, which brings me to the second part. Replacing system ("pause"); in a way that always works is tricky. Your best bet is usually to live with a less-than-perfect solution, or as I like to do, one that isn't guaranteed to do exactly what it says:

std::cin.get(); //this consumes the left over newline and exits without waiting

Okay, so cin.get() didn't work. How about this:

std::cin.get(); //consume left over newline
std::cin.get(); //wait

That works perfectly, but what if you copy-paste it somewhere where the newline isn't left over? You'll have to hit enter twice!

The solution is to clear the newline (and anything else) out, and then wait. This is the purpose of cin.sync(). However, as seen in the notes section, it is not guaranteed to clear the buffer out like it says, so if your compiler chooses not to, it can't be used. For me, however, it does exactly that, leaving a solution of:

std::cin.sync(); //clear buffer
std::cin.get(); //wait

The main bad thing about system("pause"); is that you have no idea what program it will run on someone else's computer. They could've changed pause.exe or put one that's found first, and you have no way of knowing. This could potentially ruin their computer due to it being possibly any program.

std::cin input with spaces?

You have to use cin.getline():

char input[100];
cin.getline(input,sizeof(input));

C++ Input String with Spaces

I can't comment yet, don't have enough points, but did you try adding cin.ignore(); before the getline(cin, name, '\n'); ?

Like this:

string setBusinessName()
{
string name = "";
cout << "The name you desire for your business:";
cin.ignore();
getline(cin, name, '\n');
cout << name;
return name;
}

Cin input with a + causes next input to be a string

The problem

Your programme does not work exactly as intended, because it doesn't take into consideration potentially consumed but lost characters.

Here are different cases that work as expected:

  • abc: the first char read is not numeric, so it's not consumed and cin fails fast. The second reading reads every chars present as a string.
  • 123abc456: the first 123 is read. When a is encountered, it is not consumed since it's not valid numeric. Further reading is stopped, but a numeric value could be read.
  • /123: the first char read is not numeric, so it's not consumed and cin fails. the second reading reads every char present as string.
  • -123 or +123: the first char is considered as a valid numeric char and is read, and then the remainder is read, still as a numeric value. Works as expected if you consider that a double ora an int can be signed. Depending on output formatting, the + might not appear with your output.

Here are the cases that do not work: if the first char is + or - but it is not followed by a valid numeric char. In this case the first char is consumed, but the next char makes the numeric input fail. The remaining chars are then read as string (except the first sign that was already consumed and is lost). Examples:

  • ++123
  • + 123 (the space ends the axtraction of the double that fails, the remainder is read as a string).

Online demo

The solution

The easiest solution is to read the input as a string, then try to convert the string.

For example:

size_t processed;
string hi;
double hello;
cin >> hi;

try {
hello = stod(hi,&processed);
cout<<"number:" <<hello;
if (processed<hi.size())
cout << " (followed by something)";
cout <<endl;
}
catch (...) // should be more precise in catching, but it's for the proof of concept
{
cout <<"string: "<< hi << endl;
}

Online demo

If you want to consider + and - as alphanumeric, it'd be easy to check if hi is non empty and hi[0] a digit before trying to do the conversion.

Alternatively, you could also do a regex check of the string to see if it matches a numeric format.

How to read an input string in c++, ignoring spaces

My apologies again. Post edit, I think my initial comment was correct-ish. Get the line with getline as recommended by others. Then put the line in a std::istringstream. Read the words from the stringstream with >> and concatenate them with the + operator until you have assembled one of the tokens you are looking for. >>'s default behaviour is to discard all whitespace for you.

So...

std::string line;
while (std::getline(cin, line)) // reads in a line
{
std::istringstream stream(line);
std::string spaceless;
std::string word;
while (stream >> word) // get words on the line without any whitespace
{
spaceless += word; // assemble without spaces
if (spaceless == "shorttonnes")
{
//do something with spaceless
}
else if (spaceless == "Someothertoken")
{
// do something else with spaceless
}
else if ( ... )
{
// rinse, repeat
}
}
}

Here is a simple, stripped down example of just the concatenation: https://ideone.com/hGLr6f

There are other techniques you can use in place of the if/else if chain. A std::map of strings and function pointers for one, but that is another question.



Related Topics



Leave a reply



Submit