How can I check that the user actually is inputting what I want them to?
(For example letters or numbers);

I need the user to input y or n, so here is how i tried to solve it:

char answer;
do
{
    system("cls");
    cout <<"Want to play? <y/n>: ";
    cin>>answer;
}while(tolower(answer)!='y' && tolower(answer) != 'n');

while(answer=='y')
{
    //some game or whatever
    cout <<"weee, again?";
    cin>>answer; //again?
}

Any good?
Seems to me like I would have to do a while loop for every input so I know they're not inputting something else than what I want (letters/numvers/etc)
Isn't there a better way? There has to be...?

Also, with this code, if I just press enter it will go to the next line can I fix that?
It doesn't count it as an input - I think - it just jumps to the next line...

Recommended Answers

All 10 Replies

Isn't there a better way?

Not really. You can take raw input and gain more control over exactly what characters are accepted, but that has its disadvantages as well. Typically, reading unformatted input as a string, then validating it and responding accordingly is the recommended approach.

sha11e, you may look into the cin.good(), cin.bad(), and/or the cin.fail() commands. I believe those could help you here. YOu could have it set up to say something like:

if(cin.fail(variable))
{
//do this
}
else
{
//do that
}

I'd look into that, maybe. It may help. :)

you may look into the cin.good(), cin.bad(), and/or the cin.fail() commands. I believe those could help you here

Perhaps you should do a little research on those member functions, as your suggestion is completely nonsensical.

you could creat a couple of function like GetLetterInput and GetNumberInput and have them do the work so in your main function you wouldn't have to do all of the data validation. an example of how GetLetterInput might work is,

ifstream & GetLetterInput(ifstream & stream, int & input)
{
    int number = 0;
    string temp;
    for(;;)
    {
        cin >> temp;
        number = atoi(temp.c_str());
        if (number != 0)
        {
            input = number;
            return stream;
        }
        else if (number == 0 && temp.size() == 1 && temp[0] = '0')
        {
            input = number;
            return stream;
        }
        else
            cout << "Invalid Input.  Please enter a number: ";
    }
}

this is just an example and i have not verified that this works

There are about ten million ways to go about input validation, but it's a good idea to use full line input to avoid the classic input stream "flushing" issues:

#include <cctype>
#include <iostream>
#include <sstream>
#include <string>

namespace {
    void show_menu()
    {
        std::cout<<"Want to play? <y/n>: ";
    }

    template <typename T, typename Pred>
    bool valid_input(T& input, Pred is_valid, bool show_message=true)
    {
        std::string line;
        bool valid = getline(std::cin, line);
            
        if (valid) {
            std::istringstream iss(line);
            valid = iss>> input && is_valid(input);
        }

        if (!valid && show_message)
            std::cout<<"Invalid input.\n";

        return valid;
    }
}

int main()
{
    const auto valid_answer = [](char x)->bool {x = toupper(x); return x == 'Y' || x == 'N';};

    char answer;

    do {
        show_menu();
    } while (!valid_input(answer, valid_answer));

    std::cout<< answer <<'\n';
}

Not really. You can take raw input and gain more control over exactly what characters are accepted, but that has its disadvantages as well. Typically, reading unformatted input as a string, then validating it and responding accordingly is the recommended approach.

Help ;(
I want the user to input either j or n.
If I use a char, one could input "jbbb4935257b" and it would only store 'j'.
So when they actually input more than just j or n, it can still accept it - as long as it starts with either j or n.

Can you give me an short example of how to solve it? ;/

Just:
1. "input j or n please"
2. check if they did

In my example, the change is a simple one: just check for end-of-file on the stringstream:

template <typename T, typename Pred>
bool valid_input(T& input, Pred is_valid, bool show_message=true)
{
    std::string line;
    bool valid = getline(std::cin, line);
            
    if (valid) {
        std::istringstream iss(line);
        valid = iss>> input && is_valid(input) && 
            iss.peek() == std::char_traits<char>::eof();
    }

    if (!valid && show_message)
        std::cout<<"Invalid input.\n";

    return valid;
}

Once again, there are a number of ways to accomplish what you want, and they all depend on the method of input/validation you're using as to which is better.

template <typename T, typename Pred>
bool valid_input(T& input, Pred is_valid, bool show_message=true)
{
    std::string line;
    bool valid = getline(std::cin, line);
            
    if (valid) {
        std::istringstream iss(line);
        valid = iss>> input && is_valid(input) && 
            iss.peek() == std::char_traits<char>::eof();
    }

    if (!valid && show_message)
        std::cout<<"Invalid input.\n";

    return valid;
}

I.... I.. I don't even....
I didn't understand 1 line of that o.O
Anyway... I'm going with a string and checking j and J and n and N.
Lame solution, but it'll have to do.

I didn't understand 1 line of that o.O

Okay, let's peel away some of the more advanced layers and look at what's really going on under the surface:

#include <cctype>
#include <iostream>

namespace {
    void show_menu()
    {
        std::cout<<"Want to play? <y/n>: ";
    }

    bool valid_input(char& input)
    {
        bool valid;

        if (std::cin>> input) {
            char x = toupper(input);

            if (x == 'Y' || x == 'N') {
                // It's a valid character, now check for "end-of-file"
                if (std::cin.peek() == '\n' ||
                    std::cin.peek() == std::char_traits<char>::eof())
                {
                    valid = true;
                }
                else {
                    // Not the end of input
                    valid = false;
                }
            }
            else {
                // Not a valid character
                valid = false;
            }
        }
        else {
            // Failed to read anything
            valid = false;
        }

        if (!valid)
            std::cout<<"Invalid input.\n";

        return valid;
    }
}

int main()
{
    char answer;

    do {
        show_menu();
    } while (!valid_input(answer));

    std::cout<< answer <<'\n';
}

This simplified version does the same thing, except with cin directly instead of reading a whole line. You shouldn't have any trouble with the code barring the test for "end-of-file". cin.peek() will look at the next character in the stream without extracting it. If that character is either a newline or a true end-of-file, the assumption is that what cin initially read is the entirety of what the user typed.

Perhaps you should do a little research on those member functions, as your suggestion is completely nonsensical.

You're right. >.> Sorry, I was looking at this from the wrong perspective...

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.