**Hi there,

I'm new to C++ (bet you guys don't hear that very often!!) and what I'm trying to do, in a console application, is this:

  1. Ask for a number
  2. If the user input isn't a valid float, get angry and go back to 1.
  3. If the user input is a float, take the user input and print it back
  4. Use a function to print back the number, doubled, on a new line
  5. Count down from 5 and exit

I have it all apart from the if statement. How do I have the program test for a float and act upon it? I was playing around with goto and a label earlier, but that was just awful.

This is my code so far:

#include "stdafx.h"
#include <iostream>
#include <Windows.h>


float doubledNumber;                                                
float x;                                                        
float doubler (float operand)                       
{
    doubledNumber = operand * 2;                         
    return doubledNumber;                                       
}


int main()
{
    std::cout << "Please enter a number\n";
    std::cin >> userInput;                                              
    std::cout << "The number you entered is " << userInput << ;       
    std::cout << "\nThis number, doubled, is ";                   

    std::cout << doubler (userInput);                                 
    std::cout << "!\n";
    Sleep (1000);                                               
    std::cout << "Exiting in 5...";
    Sleep (1000);                                               
    std::cout << "4...";
    Sleep (1000);
    std::cout << "3...";
    Sleep (1000);
    std::cout << "2...";
    Sleep (1000);
    std::cout << "1...";
    Sleep (1000);
    return 0;

}

At the moment, if I enter anything that isn't a number, it calculates based on 0.

Thanks in advance for any replies! I know this is basic stuff, but I've always found interacting and discussing with other programmers easier than pounding pages.

Just realised that I'd still entitled this "bit of weirdness". That was with regards to "goto" that I was trying earlier; I looked it up and everyone seems to agree that goto is obsolete.

To test for valid input you generally want to take the input in as a string and check to see if it satisfies the conditions for the type of input you want. If it does than you convert it to the type you want. So if you want to see if the user entered a valid float than you would make sure that it follows the syntax for a float.

Can it have an “-“? Yes, Only one though. Where? Only at the beginning.
Can it have an “.”? Yes, Only one though. Where? As long as there is only one and it comes after a “-“ if there is one.

These are the kinds of steps you have to take to validate string input. I could go on but I would like to see what you can come up with. BTW you can use c-style string or you can use the string type from the STL for this

You can also check if its float or not, without using string.

Here is an algorithm :-

  1. Take input in float type.
  2. Type convert it to int and store it in a new variable ( I'm taking integer part of input, in mathematical term, I'm taking the greatest integer less than or equal to it , which is [x] ).
  3. Subtract this new variable in integer datatype from original which was in float.
  4. Check whether answer is equal to 0 or not. If 0 then the original input was integer, else it was float.

Make a function that performs this above task.

@np complete
What your idea does is make sure there is a decimal portion to the number. But 5.0 is a valid floating point number.

What the OP need to do is basically what NathanOliver describes.

I'm new to C++ (bet you guys don't hear that very often!!)

Nope. Never. :P
What I want to know is why everyone thinks they have to tell us that. It's bleeding obvious based on the question and the code!

Just realised that I'd still entitled this "bit of weirdness".

which is technically in violation of the Member Rules: "Do use clear and relevant titles for new articles". Use a title that give us an idea why you are posting. In this case "Testing Input Validity" or something like that would be a proper title.

That was with regards to "goto" that I was trying earlier; I looked it up and everyone seems to agree that goto is obsolete.

It's not that it's obsolete (it isn't). It's just bad practice.

Look at NathanOliver algorithm and I have two questions... Is string "+0.5" a float? Or Is string "+.7" a float? That may clear up a bit for the algorithm...

Take the input into a string, the use the strtof(const char* ptr, char** endptr) function to convert the string to a number. You pass the address of a char* variable as endptr and if the conversion stops because it encounters a non-float character in the string, endptr will be set to the location in the string where that occurred. At that point, you can determine whether to compute the results, or output an error message. Bear in mind that strtof() and strtod() will both handle scientific notation such as "1.25E22", as well as hexadecimal and octal numbers, so if you want to be more rigorous in your treatment of the input you will need to walk the string and decide whether or not you want to accept it.

Got it! (Sort of).

New code:

#include "stdafx.h"
#include <iostream>
#include <string>
#include <Windows.h>
using namespace std;

float doubledNumber;                                                                                                        
float doubler (float operand)
{
    doubledNumber = operand * 2;                         
    return doubledNumber;                                       
}

int main()
{
    float userInput;
    std::cout << "Please enter a number\n";
        if (!(cin >> userInput))
        {
            cout << "BAAAAAD USER! I SAID NUMBER!";
        }
        else
        {
        std::cout << "GOOOOOD USER! YOU ENTERED: " << userInput ;       
        std::cout << "\nThis number, doubled, is ";
        std::cout << doubler (userInput);
        std::cout << "!\n";
        }
    Sleep(2000);
    }

Just need to throw a loop over it to revert back to the start upon an invalid input now.

My other idea was to convert the string to an array and then check each object in the array with isdigit, which would work better - at the moment, if the user for instance types "Number is 34" they will get an error (which is what I want) but if the user types "34 is the number" the program will accept that as valid input, which isn't really what I want. But I'm a lot closer than I was this time yesterday!

Using this approach if you use a loop to go back and ask the user for a number if they dont make sure you clear the error flags from cin. Otherwise the flags will stay set and you will always get the error message saying you didn't enter a number even though you did. I would like to add that there are better ways to go about doing this. Here is a little sinpet that will do a little error checking but there are better ways.

#include <sstream>
#include <iostream>
#inlcude <string>

using namespace std;  // just for the example

int main()
{
    float number;
    stringstream ss;
    string input;

    bool goodInput = false;

    while (!goodInput)
    {
        cout << "Please enter a decimal number: ";
        getline(cin, input);
        ss << input;  // puts input into the stringstream
        ss >> number;
        if(!ss.eof())  // was all we got an number?
            cout << "Please enter a decimal number!\n";
        else
            goodInput = true;
    }
    return 0;
}

Thanks for that... A few bits of that are new to me, I'll look into them!

Speaking of re-using cin, I've run into a couple of issues with that. Namely:

  1. I've been using cin.get() before the main function returns, to enable the program to pause so I can see the output. This works fine, until...
  2. I use cin to get user input earlier in the program. If this is the case, the cin.get() at the end of the program won't do anything (which is why I've started to use sleep(2000) to make the program pause for a couple of seconds for me to have a look).

I read that cin.clear() would let me re-use cin, but this isn't the case; if I have cin.clear() and then cin.get(), the program still doesn't wait for input at the cin.get().

Any ideas? Am I misunderstanding cin?

Any ideas? Am I misunderstanding cin?

Yes.

Using cin.getline() reads the entire line so you don't have to worry about characters left in the input buffer.

Speaking of re-using cin, I've run into a couple of issues with that. Namely:

  1. I've been using cin.get() before the main function returns, to enable the program to pause so I can see the output. This works fine, until...

Remember, cin.get() reads a single character. When you get to a prompt that says "Enter a character:" and you type in 'A', how many keys do you actually hit? Therefore, how many characters?

  1. I use cin to get user input earlier in the program. If this is the case, the cin.get() at the end of the program won't do anything

Yes, it does something. It read a character from the input stream. See above.

I read that cin.clear() would let me re-use cin, but this isn't the case; if I have cin.clear() and then cin.get(), the program still doesn't wait for input at the cin.get().

That's because cin.clear() doesn't do what you read... Look it up at a reputable site...

cin (and other istreams) is a bit complicated to grasp at first, but here's the basic information you need to know:

cin is a buffer of data that accumulates whatever the user inputs, which it can then feed by various "extraction" methods. So, when the user writes something and then hits the enter-key, that data is placed on the buffer (internal to cin). When your program executes a line like cin >> userInput, the data is inspected (starting from the beginning of the buffer) for a floating-point value. It will skip meaningless characters like spaces, tabs, and new-lines, and will make sure there is a valid floating-point value there. If valid, it will set userInput to that value and will remove the extracted characters (skipped characters plus those making up the floating-point value) from the cin buffer. If invalid, it will leave the buffer intact and set an internal error flag (failbit to be precise). This sets cin into an error-state. When you evaluate it with !cin (or compounded as !(cin >> userInput)), it will be "true" if cin is in an error-state.

There are two things to notice. First, after one input failed, cin is in an error-state, which it will not "forget" on its own, you must tell it to forget about that error. This is what the function cin.clear() does, it tells cin to forget about its error-state. The second thing to notice is that extracting things from cin doesn't always extract everything from it. In fact, most of the time, when you extract something from cin, it only extracts what is asked for (e.g., the float), and leaves the remaining characters there. These need to be "flushed" if you want a fresh start at using cin for more inputs. For example, if I enter "23 is a number" and I extract a float from it, then after the extraction, cin will still contain " is a number" pending on its buffer. Afterwards, if I enter "42.0" and try to extract a float from cin, it won't work because, at this point, cin's buffer reads as " is a number\n42.0\n" ("\n" represents a new-line) because what was newly written just gets added at the end of what was already in the buffer. To tell cin to ignore what is left on the buffer, use the function cin.ignore(); which tells it to seek the next new-line character on the buffer, and flush everything prior to it (inclusively). And this explaination should explain the behavior you've been experiencing with using cin.get(); to pause the program (which is a fine method to do it).

So, your program should probably be as so:

float userInput;
cout << "Please enter a number\n";
while( !(cin >> userInput) ) {
    cout << "BAAAAAD USER! I SAID NUMBER!\n";
    cin.clear();   // clear error-state on cin.
    cin.ignore();  // ignore the last input (start fresh).
};
// at this point, the userInput should be valid:

cin.ignore();  // always good to flush cin after a numeral input.

std::cout << "GOOOOOD USER! YOU ENTERED: " << userInput ;       
std::cout << "\nThis number, doubled, is ";
std::cout << doubler (userInput);
std::cout << "!\n";

^ Loved that post. That explained a lot about cin.

As usual (for me anyway!) an answer has provided more questions.

Taking into account that cin.clear() clears the error state, and cin.ignore(), I added one of each after each possible case in the "if" statement. This, to me, says that whatever the outcome, the cin buffer will be emptied and cleared of its failbit, no matter what the outcome of the "if".

However...

#include "stdafx.h"
#include <iostream>
#include <string>
#include <Windows.h>
using namespace std;

float doubledNumber;                                                                                                        
float doubler (float operand)
{
    doubledNumber = operand * 2;                         
    return doubledNumber;                                       
}

int main()
{
    float userInput;
    std::cout << "Please enter a number\n";
        if (!(cin >> userInput))
        {
            cout << "BAAAAAD USER! I SAID NUMBER!";
            cin.clear();                            //clear buffer on bad input
            cin.ignore();
        }
        else
        {
            std::cout << "GOOOOOD USER! YOU ENTERED: " << userInput ;       
            std::cout << "\nThis number, doubled, is ";
            std::cout << doubler (userInput);
            std::cout << "!\n";
            cin.clear();                           //clear buffer on good input
            cin.ignore();
        }
    cin.clear();                 //added one more flush and clear outside of the
    cin.ignore();                //"if" brackets, in case that made a difference...
    cin.get();
    return 0;
    }

This doesn't work. Or, more precisely, it works half of the time; upon a valid input, the program executes as planned. But upon an invalid input, it displays the cout, but ignored the cin.get() at the end (the program exits immediately upon invalid input). So I guess there must be something left in the cin buffer somehow...

If you read my post you could get rid of all that error fixing and handle the input of "53 is the number" which you claim is an error but all these cin.clears and cin.ignore()s don't handle at all.

OK. So I've been experimenting with getline and stringstream.

New code:

#include "stdafx.h"
#include <sstream>
#include <iostream>
#include <string>
using namespace std;

float doubledNumber;                                                                                           
float doubler (float operand)                                       
{                                                                   
    doubledNumber = operand * 2;                                    
    return doubledNumber;                                           
}

int main()
{
    float userInput;                                                
    stringstream ss;                                                
    string input;                                                   
    bool goodInput = false;                                         
    while (!goodInput)                                              
    {   
        cout << "Please enter a number: ";                            

        getline(cin, input);                            
        ss << input;                                              
        ss >> userInput; 
        if(!ss.eof())                                              
            { 
            cout << "BAAAAD USER! "; 
            cin.clear();                           //shouldn't this clear the error?
            }
        else
            {
            std::cout << "GOOOOOD USER! YOU ENTERED: " << userInput ;       
            std::cout << "\nThis number, doubled, is ";
            std::cout << doubler (userInput);
            std::cout << "!\n";
            cin.clear();                           
            cout << "Press Enter to exit...";
            cin.ignore();
            goodInput = true;
            }
    }
    return 0;
}

Again, upon a good input (a number), this code is fine.
Upon a bad input the program loops back correctly and asks again for a number, but regardless of what is entered next (valid or invalid), it treats it as incorrect, and asks again for a number.

I tried putting a cin.clear() in there to clear the error flag; no dice. I've moved it around a few times, too; and also tried putting cin.ignore(); in there. Whatever happens, once the program has received an invalid input, it treats any input thereafter as invalid.

Any ideas why this might be??

EDIT: I think I need to clear the string at each looping... Otherwise the getline will just be added to the string. Looking into it...

^^ OK, so the problem isn't clearing the string as that gets automatically done each time. I'm just having no luck clearing the cin buffer, I guess.

Question: If I type cout << cin;, should I be shown the current contents of the cin buffer? When I do this it gives me a hex value (I think) and I'm not sure what this represents.

cin is fine too. What you need to do is clear your stringstream's buffer and state before you use it again.
Either add this here -> ss.str(""); ss.clear(); before using ss or create ss right before you use it.

Also, the condition in your if statement should be !ss || !ss.eof().
As it is now, it doesn't work as you want if the user enters a blank line.

Score! Works perfectly now.

I'll leave the code here; there are quite a few threads about on user input validation, and few of them have a happy ending. Hopefully this can help someone:

#include "stdafx.h"
#include <sstream>
#include <iostream>
#include <string>
using namespace std;

float doubledNumber;                                                                                           
float doubler (float operand)                                       
{                                                                   
    doubledNumber = operand * 2;                                    
    return doubledNumber;                                           
}

int main()
{
    float userInput;                                                
    stringstream ss;                                                
    string input;                                                   
    bool goodInput = false;                                         
    while (!goodInput)                                              
    {   
        cout << "Please enter a number: ";                            
        getline(cin, input);                            
        ss << input;                                              
        ss >> userInput;                                            
        if(!ss || !ss.eof())                                               
            { 
            cout << "BAAAAD USER! ";
            ss.clear();
            ss.str("");
            }
        else
            {
            std::cout << "GOOOOOD USER! YOU ENTERED: " << userInput ;       
            std::cout << "\nThis number, doubled, is ";
            std::cout << doubler (userInput);
            std::cout << "!\n";
            cin.clear();                           
            cout << "Press Enter to exit...";
            cin.ignore();
            goodInput = true;
            }
    }
    return 0;
}

Thanks guys!

Actually, one more question:

"Also, the condition in your if statement should be !ss || !ss.eof().
As it is now, it doesn't work as you want if the user enters a blank line."

The !ss.eof(); I understand - it satisfies the if condition if there is more to be read from ss.

But !ss... what is this? I get that it works, but I'm curious as to how. !ss means "if ss is false", but surely once ss has been emptied to userInput it is empty, and therefore false? Or is the emptiness in fact nonzero and therefore true?

The !ss part essentially checks whether or not you got a (valid) value for your variable.

This should clear things up a bit more.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.