2

I have been trying to incorporate a check to see if the input from the user is a valid input. For example my program wants the user to guess a number between 1-1000. My program works perfectly, except when the user inputs any other character other than a number it goes CRAZY. Anyways, I want it to check and make sure that the user is inputting numbers, not something silly. So I have been going in circles trying to figure this part out. I am sure it is a easy fix, but I am new to programming and this has got me stumped. Any help would be appreciated.

#include "stdafx.h"
#include<iostream>
#include<cstdlib>
#include<ctime>

using namespace std;

int main()
{

    bool isGuessed=true;
    while(isGuessed)
    {
        srand(time(0));
        int number=rand()%1000+1;
        int guess;
        char answer;


        cout<<"Midterm Exercise 6\n";
        cout<<"I have a number between 1 and 1000.\n";
        cout<<"Can you guess my number?\n";
        cout<<"Please type your first guess:\n\n";
        cin>>guess;


    while(guess!=number)
    {



        if(guess>number)
        {
            cout<<"\nToo high. Try again!\n\n";
            cin>>guess;
        }

        if(guess<number)
        {
            cout<<"\nToo low. Try again!\n\n";
            cin>>guess;
        }
    }
    if(guess==number)
        { 
            cout<<"\nExcellent! You have guess the number!\n";
        }
            cout<<"Would you like to play again (y or n)?\n\n";
            cin>>answer;
            cout<<"\n";

    if(answer!='y')
        {
            isGuessed=false;
            cout<<"Thanks for playing!\n\n";
            system ("PAUSE"); 
            return 0;
        } 

    }


    return 0;
}
Dewayne Phillips
  • 29
  • 1
  • 2
  • 8

2 Answers2

8

Here's a snippet I like to keep around for using in these sorts of situations.

int validInput()
{
    int x;
    std::cin >> x;
    while(std::cin.fail())
    {
        std::cin.clear();
        std::cin.ignore(std:numeric_limits<std::streamsize>::max(),'\n');
        std::cout << "Bad entry.  Enter a NUMBER: ";
        std::cin >> x;
    }
    return x;
}

Then any place you want to use cin>>guess, instead, use guess = validInput();

Code Man
  • 105
  • 1
  • 2
  • 14
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • 2
    Nitpick: Instead of 1000, you should use `std:numeric_limits::max()` just so you catch the inevitable person who will input a line over 1000 characters long – Sam Cristall Sep 26 '13 at 02:33
  • So basically I should wrap everything that you mentioned inside of this code you gave? – Dewayne Phillips Sep 26 '13 at 02:39
  • @Dewayne, it's probably easiest to simply write a function out of this. I will edit my original answer to be more clear on how to use this as a function. Are you comfortable with using functions yet? – nhgrif Sep 26 '13 at 02:46
  • Kind of... give it a whirl. – Dewayne Phillips Sep 26 '13 at 02:49
  • Guess i've got got it down. I know you have been really helpful but I am still not sure where to put this. – Dewayne Phillips Sep 26 '13 at 03:05
  • Put the code block in my answer between `using namespace std;` and `int main()`. And as I said, put `guess = validInput();` in place of all instances of `cin>>guess`. Then look up some tutorials about using functions. – nhgrif Sep 26 '13 at 03:08
  • Thanks, I got it to work like you said. I appreciate your time on this. I checked the box. – Dewayne Phillips Sep 26 '13 at 03:25
3

Since spreading around code similar to what @nhgrif suggests for every acquisition is tedious and error-prone, I usually keep around the following header:

#ifndef ACQUIREINPUT_HPP_INCLUDED
#define ACQUIREINPUT_HPP_INCLUDED

#include <iostream>
#include <limits>
#include <string>

template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
    do
    {
        Os<<Prompt.c_str();
        if(Is.fail())
        {
            Is.clear();
            Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        }
        Is>>Result;
        if(Is.fail())
            Os<<FailString.c_str();
    } while(Is.fail());
}

template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
    InType temp;
    AcquireInput(Os,Is,Prompt,FailString,temp);
    return temp;
}

#endif

Usage example:

//1st overload
int AnInteger;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);

//2nd overload (more convenient, in this case)
int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");

The AcquireInput function allows to read any type for which there's an operator>> available and automatically retries (cleaning up the input buffer) if the user inserts invalid data. It also prints the given prompt before asking the data and the error message in case of invalid data.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299