How To Test For Correct Input In C++?


Recommended Posts

ok I have a problem,

I have a program that runs but only if you put the correct type of input.. ie I have a int feet

if on cin >> feet

the user puts: a

it put a loop that confuses the program requiring cntrl-c to stop

is there a way to test this varable to see if the input type is correct?

also I am using -1 as a end condetion (teachers choice)

while it runs, And I know that the teacher would accept it as its is as the book has no mention of testing input. I do not think its a good ideal to put out software if the user can mess it up by putting a wong input type/

Link to post
Share on other sites

Right, the fail() member function will do the trick.

$ cat t.cc
#include <iostream>

using namespace std;

int main()
{
   while (true) {
       int i;
       // Prompt
       cout << "val: ";
       // Flush cout to force prompt to be printed
       cout.flush();
       cin >> i;
       if (cin.fail()) {
           cerr << "invalid input" << endl;
           // Clear failure/error flags
           cin.clear();
           // Drop character that caused failure
           cin.ignore();
       } else {
           if (i != -1) {
               cout << "value: " << i << endl;
           } else {
               return 0;
           }
       }
   }

   return 0;
}

$ g++ t.cc
$ ./a.out
val: 1
value: 1
val: 2
value: 2
val: 3
value: 3
val: a
invalid input
val: -1
$

There's no reliable way to use the value returned by operator>>() to determine if there was a failure.

Edited by jcl
Link to post
Share on other sites

I get everything you did (thanks to comments.) but I do not get the two return 0;

if ?I have a return 0 at the end do I need it in a else.. or can I dope the else all together??

is that even aprt of the error checking

as my if ( != -1) looks like this (noticed the check OS function I barrowed from you)

#include <iostream>
#include <cstdlib> //needed for system calls
using namespace std;// this is used instead of calling all the using std::cout or defining each std out


void clear_screen() // this is for portability of system call you must us the -DUNIX or -DWIN32 option for gcc
{
#if defined WIN32 // compiler replaces clear_screen() with system("cls"); if -DWIN32 is used with gcc
          system("cls");
#elif defined UNIX // compiler replaces clear_screen() with system("clear") if -DUNIX is used with gcc
             system("clear");
#endif
}


//Main Function
int main()
{
       int miles, MgCounter = 0;//initalize varables for holding miles and the counter for loop
       double gallons,  totalMg, average, finalMg; //initalize double for decmial point

       //clear screen call
       clear_screen();//call the correct clearscreen function for your system based on the -D compile option for VC++ ??

       //process phase, also loads one input before the loop
       cout << "Enter the Gallons used (-1 to end) : ";//prompt for gallons
       cin >> gallons;//input for gallons

       //start while not loop
       while (gallons != -1) {
               cout << "Enter Miles Driven: ";
               cin >> miles;//prompt for miles

               //start math
               average = miles / gallons;//divide miles by gallons to get average
               totalMg += average;// adds average to totalMg
               ++MgCounter;//increment MgCounter
               cout << "The Miles / Gallon for this tank was " << average << endl;//output this tank

               //next round of input
               cout << "\nEnter the Gallons used (-1 to end) : ";//prompt for gallons
               cin >> gallons; //input for gallons
       }//end while

       if (MgCounter != 0) {
               finalMg = totalMg / MgCounter; // math for final calculation
               cout << "\nThe overall average miles/gallon was " <<  finalMg <<  endl;
       } // end this part of if statment go to else

               else
                       cout << "you did not enter any information to calculate" << endl;
       return 0;// returns function competion value
}

if I got what you said it should look like this

#include <iostream>
#include <cstdlib> //needed for system calls
using namespace std;// this is used instead of calling all the using std::cout or defining each std out


void clear_screen() // this is for portability of system call you must us the -DUNIX or -DWIN32 option for gcc
{
#if defined WIN32 // compiler replaces clear_screen() with system("cls"); if -DWIN32 is used with gcc
          system("cls");
#elif defined UNIX // compiler replaces clear_screen() with system("clear") if -DUNIX is used with gcc
             system("clear");
#endif
}

// function to check if a bad input was entered in to program, and ends program
int error_check()
{

 if (cin.fail()) {
     cerr << "invalid input" << endl;
   // Clear failure/error flags
     cin.clear();
  // Drop character that caused failure
     cin.ignore();
   }//end if
  return 0;
}

//Main Function
int main()
{
       int miles, MgCounter = 0;//initalize varables for holding miles and the counter for loop
       double gallons,  totalMg, average, finalMg; //initalize double for decmial point

       //clear screen call
       clear_screen();//call the correct clearscreen function for your system based on the -D compile option for VC++ ??

       //process phase, also loads one input before the loop
       cout << "Enter the Gallons used (-1 to end) : ";//prompt for gallons
       cin >> gallons;//input for gallons

       error_check();


       //start while not loop
       while (gallons != -1) {
               cout << "Enter Miles Driven: ";
               cin >> miles;//prompt for miles

               error_check();

               //start math
               average = miles / gallons;//divide miles by gallons to get average
               totalMg += average;// adds average to totalMg
               ++MgCounter;//increment MgCounter
               cout << "The Miles / Gallon for this tank was " << average << endl;//output this tank

               //next round of input
               cout << "\nEnter the Gallons used (-1 to end) : ";//prompt for gallons
               cin >> gallons; //input for gallons
               error_check();

       }//end while

       if (MgCounter != 0) {
               finalMg = totalMg / MgCounter; // math for final calculation
               cout << "\nThe overall average miles/gallon was " <<  finalMg <<  endl;
       } // end this part of if statment go to else

               else
                       cout << "you did not enter any information to calculate" << endl;
       return 0;// returns function competion value.. really not needed for main but makes a nice output for other programs
}
                                               

This is primive in doing this but it has a effect that works.. I just need to adapt it to work better and have it exit the program or maybe the inputs need to be functions?? so I can rerun them incase of error

Link to post
Share on other sites
I think what you are looking for are 'checks'. Try reading here:

http://www.besttechie.net/forums/index.php...indpost&p=14082 for more info on those. (thats the post talking about them, but you may need to read the whole thread) I never got to understanding them yet, but see if that helps.

Matt

thanks ..I had read that but I could not see the answer in their.. untill now.. sometimes I'm slow

Link to post
Share on other sites
I get everything you did (thanks to comments.) but I do not get the two return 0;

if ?I have a return 0 at the end do I need it in a else.. or can I dope the else all together??

The one at the end of main() is force of habit; the first thing I write in main() is a return statement. It doesn't do anything in this case, but it doesn't hurt.

The one in the else, on the other hand, is responsible for terminating the program when it receives a -1, so it has be there. (Or something has to be there anyway; it could replaced with some other transfer of control to break out of the while loop. Break or goto would work.)

as my  if ( != -1) looks like this (noticed the check OS function I barrowed from you)

That's fine. Probably better, actually. I debated how to write the loop but decided that it would clearest if I made all the tests explicit. I don't really like the cascading conditionals but they're easier to read than something like

#include <iostream>

using namespace std;

int main()
{
   int i = 0;

   while (cout << "val: " << flush, cin >> i, i != -1 && !cin.eof()) {
       cin.good() ? cout << "value: " << i << endl
                  : (cin.clear(), cin.ignore(), cerr << "invalid input" << endl);
   }
       
  return 0;
}

Aside: It occured to me that I'd forgotten to check for EOF earlier.

This is primive in doing this but it has a effect that works.. I just need to adapt it to work better and have it exit the program or maybe the inputs need to be functions?? so I can rerun them incase of error

Whatever works. There are a lot of good ways to do this sort thing; all that matters is that you're comfortable with your solution. I'd probably wrap the input stuff up in generic prompt function (I do like writing prompt functions).

Edited by jcl
Link to post
Share on other sites

xorry, by primitive I ment my soultion to use the saem error check to all input when not all input is the same

Link to post
Share on other sites

on other thing.. I would need to declare variables outside of main if I made prompt functions correct?

Link to post
Share on other sites
on other thing.. I would need to declare variables outside of main if I made prompt functions correct?

Nope, the function is all you need. For simple integer prompts this would suffice:

int prompt(const string& s)
{
   while (true) {
       int val;
       cout << s << flush;
       cin >> val;
       if (cin.fail()) {
           cerr << "invalid input";
           cin.clear();
           cin.ignore();
       } else {
           return val;
       }
   }
}

usage:

int val;
while ((val = prompt("enter value: ")) != -1) {
   // etc
}

Edited by jcl
Link to post
Share on other sites

Thanks I need to play with it.. I think I understand but I probaly do not..

i see why people hate ths stuff.

BASIC take me away..

:D

Link to post
Share on other sites

ok I think I understand..

this is a function creaded before main()

int prompt( const string& s)
{
  while (true) {
      int val;
      cout << s << flush;
      cin >> val;
      if (cin.fail()) {
          cerr << "invalid input";
          cin.clear();
          cin.ignore();
      } else {
          return val;
      }
  }
}

then in main()

I have

int val;
while ((val = prompt("enter value: ")) != -1) {
  // etc
}

but for my understanding... the while (val ) test aginst the value of the return of prompt()

and the prompt("enter val: ") tell the fiunction prompt to put enter val: into s , which is declared as a const string& type..

hmmm....

so if I did a double val insted of int I could then have my floting point and my function..

also the return val now explains how main know's the value of val..

back to playing..

thanks..

Edited by iccaros
Link to post
Share on other sites

ok here is my final code with error checking..

Could I have made it smaller?

#include <iostream>
#include <cstdlib>

using namespace std;

// this is for portability of system call you must us the -DUNIX or -DWIN32 option for gcc
// compiler replaces clear_screen() with system("cls"); if -DWIN32 is used with gcc
// compiler replaces clear_screen() with system("clear") if -DUNIX is used with gcc
void clear_screen()
{
#if defined WIN32
                  system("cls");
#elif defined UNIX
                  system("clear");
#endif
}

//this is the prompt for gallons input with type error checking
double prompt_gallons ( const string& s )
{
       while (true) {
       double gallons;
       cout << s << flush;
       cin >> gallons;
       //error check for correct type
       if (cin.fail()) {
       cerr << "invalid input \n";
       cin.clear();
       cin.ignore();
}
       else
       return gallons;

}
}


//this is the prompt for miles input with error checking
double prompt_miles ( const string& t )
{
       while (true) {
       double miles;
       cout << t << flush;
       cin >> miles;

       //error check for correct type
       if (cin.fail()) {
       cerr << "invalid input \n";
       cin.clear();
       cin.ignore();
}
       else
       return miles;

}
}

//main loop
int main ()
{
       double val, miles, MgTotal , average, finalMg, gallons;
       int  MgCounter = 0;
       clear_screen();
       while ((gallons = prompt_gallons("enter gallons used (enter -1 to end): ")) != -1 ) {
       miles = prompt_miles("enter miles: ");
       average = miles / gallons;
       MgTotal += average;
       ++MgCounter;
       cout << "The Average Miles per Gallon for this tank was " << average << endl;
}

       if (MgCounter != 0) {
       finalMg = MgTotal / MgCounter;
       cout << "\nThe overall average miles/gallon was " << finalMg << endl;
       }

       else
       cout << "you did not enter any information:" << endl;

return 0;
}

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...