Remember how I said I’m studying coding? Yeah, that’s still been completely true, I’ve just been puttering along without any real issue following my course on Udemy.com. The e-instructor described things quite well through a nice, thick accent, and anything he didn’t describe I was capable of using the twin powers of my logical brain testing things independently and StackOverflow.com to resolve.
That is, until I ran into a data validation exercise.
The instructor hadn’t gone too far into detail about the actual functions behind a lot of the directions he was giving including the use of cin.rdstate() and cin.clear();. I, and apparently a large portion of the inexperienced internet, believed that the latter function would clear the stream of console input. We were wrong. We were all horribly wrong. All it does is clear the error tag on cin and allow the stream to continue being used.
So, for example, if I had a line of code getting an input for an integer involved in my lovely while loop and instead of an integer my dog crawled on my keyboard and entered COWSARESKINNY, my program would pee itself and then pee some more as it kept trying to convince itself it was using a valid data type per my instructions.
The other thing my e-instructor had suggested doing is using cin.ignore(numeric_limits<streamsize>::max(), ‘/n’);. This essentially told my data input to ignore everything after any valid data or until a new line. This could have worked just fine, because if I entered 2ynuhdoaf4reay, I’d have an input of 2 instead, and everyone would be happy fatty fingers didn’t destroy the day. Option two in my menu said to compute the area of a square. Fantastic!
HOWEVER, my particular program then needed another integer and finally a character that’s a y/n to know whether or not to continue running, so since my stream was still full of the rest of the input that was simply ignored earlier, here is what my computer would do in response to my rabid key mashing:
Take 2 to select to use my square function, then start looking for another numeric value in the stream to use that as the length of a side. It came across a weird string of characters, which it was told to ignore and give an error message, which in my case said, “You and your silly characters! I said an integer!”. It kept pushing through this error message, clearing the screen so it’d look pretty and hide the evidence of previous errors, until finally it found what I had told it to look for. A number. The number 4. My code did a happy dance and giggled excitedly, finally computing the area of a square. 16! Hooray! Then I sent it back to my main function where it asked whether or not we wanted to calculate the area of another shape, so it then looked in the input stream for a character. r, e, a where all invalid being that they weren’t a y or an n, and so the computer spat repeatedly to enter the area of another shape until it decided to. ALL this without a human being needing to add anything else in!
I had a problem. A problem my instructor over the internet hadn’t even looked at because he hadn’t produced this case during the lesson, and while I was sure there would be a later point where data validation would be looked at further with a solution that didn’t cause my program to just auto-run itself into failure, I didn’t learn it yet. Was I particularly attached to perfecting a program that calculated the area of a shape? No. But it worked incorrectly for what I had just been supposed to learn, and darn it, I wasn’t going to fail at acquiring the expected knowledge! So I set to my problem-solving regime: a healthy mix of independent research and soliciting the aid of those I perceive as being better at what I’m trying to do than I am.
My first step was to test a few different cases to determine if my hypothesis about my error was correct. It was. Hooray! My next step was to try to figure out a way I could clear the input stream after getting the data I wanted. After trying many, many things, I finally enlisted my husband’s assistance in case he happened to know the information I was looking for.
While talking to him did further my understanding of my code produced with the aid of an online instructor, I unfortunately did realize that he didn’t know a command that would solve this problem either. The next step was to hit up the internet again, and while the internet had a variety of suggestions, none of them met the program’s outlined perimeters – that is, accepting the valid input if they typed correctly the first time but just got fatty fingers afterward. Not to say I’m against typically forcing people to enter their input correctly in order to get what they want.
My next step was to check in with my friend Michie who is a professional programmer who would like to ride off into the sunset with C++. She, also, said she typically just refused any data input that wasn’t perfect. So back to the internet I went. I finally found a post at cplusplus.com‘s forums that addressed my issue. It all seemed so simple now, but it required the use of a library I had never used before: sstream.
Here’s how it worked to the best of my knowledge. I’d get an input from cin and dump it all into a string named input. I’d then make a stringstream, which to my understanding is essentially a stream that can handle both input and output instead of just one or the other. Since I get the input initially as a string, I dump everything in my cin stream directly to my input without having to worry about some extra stuff floating around, and since stringstream can input and output, I input the stream into my integer data until it can no longer input. If it can’t add any of the stream to my integer at all, it breaks out, clears the screen, and lets me know I have another chance to try again. If I can enter a number but then have some insanity afterward, it takes the valid input and then moves on. this removed my issue of invalid information still being stored in the string afterward, because with a new input, the content of my stream is changed to the new input. Unlike just cin, I can use the stream for input and output, so I can convert the data safely from my string input to the stream to my data type. I no longer had to ignore the rest of my stream, only for my cin stream to vomit them up later when I least expected.
Thank you, stranger on the internet at the C++ forums, for helping me solve this problem! My code, while still not completely elegant, is much more functional now and forgiving to fatty fingers everywhere.