Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

[C++] Validating user input

user input

  • Please log in to reply
2 replies to this topic

#1 Xochiquetzal

Xochiquetzal

    CC Lurker

  • Just Joined
  • Pip
  • 5 posts

Posted 03 July 2007 - 03:39 PM

'ay!
Most of the programs I write are very dependent on user input (using your own programs = fun!). As such I've been googling lately for a way to validate what users write. I've found nothing that I can understand...

I just made a simple game ("guess the random number between 0 and 100 in 10 tries"). The user is supposed to input an integer (stored in the guess variable). The program bugs out if one inputs anything else (including floats), by spamming the "It's higher..." switch case. This is pretty likely a result of the program structure (it seems odd, can't put my finger on exactly what), but until I know how to improve that -- what I should do to validate that the input is an integer?

Here's my code for reference. The input-section is right after the big "The game" comment chunk.

#include <iostream>
#include <time.h>		// for rng seed

int main() {
	
	// VARIABLE INITALIZATION
	
	srand((unsigned)time(0));	// rng seed
	int number = rand()%101;	// the random number between 0-100; raN
	int guess,numberOfGuesses=0;
	std::string guessCount[10] = {
	"First", "Second", "Third", "Fourth",	// first [guess], second [guess]...
	"Fifth", "Sixth", "Seventh", "Eighth",	// represents numberOfGuesses
	"Ninth", "Tenth (last!!)" };
	
	// INTRODUCTION TO GAME
	
	std::cout << "Welcome to Xochi's Number Game!!"	<< std::endl
		<< "I have a random number between 0 and 100." << std::endl
		<< "You must try to find it within 10 tries!!\n" << std::endl;
		// introduction
	
	// THE GAME
	
	// 	the guess loop - while the number of guesses is lower than 10,
	//	it goes through this do{}: enter a number -> is guess == raN?
	//	if yes, go to else (game quit)
	//	if no, is raN<guess? write whether it is lower/higher,
	//	then go to the loop start.
	//	when numberOfGuesses==10, go to next do-loop
							
	do {
		numberOfGuesses++;	// that's one guess
		if(numberOfGuesses==10) std::cout << "\a";	// last try beep warning
		std::cout << "Enter your guess! "
		<< guessCount[numberOfGuesses-1] << " try:" << std::endl;
		// gC[nOG-1]: -1 needed due to 1st in array = [0]
		std::cin >> guess;	// input >> int guess
		// here, I need some way of validating that guess==int!


		// GUESS==RAN CHECKS AND PROCEDURES
		
		if(guess!=number) {	// guess != raN
			switch((number<guess)?1:0) {	
			// 1 = guess is lower than raN
				case 1:
				std::cout << "It's lower...\n" << std::endl;
				break;		// go to loop start, new guess
				case 0:
				std::cout << "It's higher...\n" << std::endl;
				break;		// go to loop start, new guess
				}
			}
		else {	// guess==raN;
		//exit message depends on how many tries it took to find raN
			if(numberOfGuesses==1) {
			std::cout << "Whoaaaw!! First try! That's really great!!";
			// impressive!
			exit(0); // normal program termination
				}

			else if(numberOfGuesses==2 || numberOfGuesses==3) {	
			std::cout << "You found it! It took you "
			<< numberOfGuesses << " tries." << std::endl
			<< "That's pretty nice!!" << std::endl;
			exit(0);
				}

			else if(numberOfGuesses==4 || numberOfGuesses==5) {
			std::cout << numberOfGuesses
			<< " tries! Good!" << std::endl;
			exit(0);
				}

			else if(numberOfGuesses==6 || numberOfGuesses==7) {
			std::cout << numberOfGuesses
			<< " tries... kinda average!" << std::endl;
			exit(0);
				}

			else if(numberOfGuesses==8) {
			std::cout << "8 tries eh? That's kinda lousy..." << std::endl;
			exit(0);
				}

			else if(numberOfGuesses==9) {
			std::cout << "9 tries?! That's actually terrible! Go practice even more!!"
			<< std::endl;
			exit(0);
				}
		}
	} while(numberOfGuesses!=10);
	// repeat this guess-loop until the number of guesses==10
	
	// RAN WASN'T FOUND AFTER 10 TRIES!
	
	do {	// when the number of guesses == 10 and raN not found
		std::cout << "10 tries and no match! The number was " << number
		<< ".\nPractice more and return!" << std::endl;
		exit(0); // normal program termination
	} while(numberOfGuesses==10);

	return 0;
}


  • 0

#2 v0id

v0id

    Retired

  • Retired Mod
  • PipPipPipPipPipPipPipPip
  • 2313 posts

Posted 03 July 2007 - 10:22 PM

It's generally a bad idea to use std::cin all alone. One of the most used ways to get user input, no matter type is to use strings, stringstreams and the resulting type. We can make a template function, to do this for us.
template<typename Type>
bool GetInput(Type &destination, std::istream &stream = std::cin)
{
	std::string temporaryHolder;
	std::stringstream stringStream;
	
	std::getline(stream, temporaryHolder);
	stringStream << temporaryHolder;
	
	return (stringStream >> destination);
}
This function accepts user input of any kind. You can use it with integers, floating numbers, strings, and so on. That's because that the stringstream can "convert" with these types. First we're getting the user input, exactly as it was typed, into a string. Secondly, we're giving the string to the stringstream. Thirdly, we're sending it from the stringstream to the variable the user specified. The second parameter in the function, is simply the stream to get input from - in our example std::cin, because we want user input. It could had been a file stream too.

If you then want to use the function, it's a lot easier, and you don't need to do much. F.ex. if we want to get an integer, but will prevent something like "10.001", "123hello123", and so on.
int iMyInteger;
GetInput(iMyInteger);
// iMyInteger now holds a user value
To be even more sure, that the input actually worked, we can check it with the boolean value the function returns.
if(GetInput(iMyInteger))
    // Everything went fine
else
    // Everything went... wrong
As you can see you've a lot control, and it's easy to use.

I've other optimization tips for you as well.
You need to look at your headers, but also the headers and what the program actually uses of functions, objects, etc. First take a look at second line, where you're including the time header. In the way you're doing it, it's deprecated. In C++, all the old standardized libraries, have gotten "new names" if we can say that. So instead of the ".h" in the end, you put a 'c' in the start. It's not only for the time library, but also for stdlib, stdio, and so on.
#include <ctime>
#include <cstdlib>
#include <cstdio>
// ...
Now you've to look at the rest of the program too. You're using a lot of functions and objects, without including the headers for 'em. The first that felt into my eyes were std::string. You don't even includes the string library. You should. The second is exit(), which is btw not used anymore in C++. Alternatives would be std::exit(), or the good old return-statement, to do the same.

My last tip, is not something you've to change, but it is much easier to use, to you might want to think about it. It's how you're handling the different numbers, when printing the message about how many guesses you used for finding the right number. You're using if-statements... that's just fine, but with a single switch-statement, the code will be much nicer and cleaner. To "support" multiple cases, you can do as following.
case 1:
case 2:
case 3:
    // Do something, if the number was 1, 2 or 3.
    break;
When you're using exit() - or if it was me, a return-statement, you don't even need the break neither. Because when using those functions, the break-statement will never be executed anyway.

I've decided not to post the corrected code, so you've to do something by yourself. If you want me to post it, I'll post it in here, so you can take a look at it.
  • 0
If you enjoy reading this discussion and are thinking about commenting, why not click here to register and start participating in under a minute?

#3 Xochiquetzal

Xochiquetzal

    CC Lurker

  • Just Joined
  • Pip
  • 5 posts

Posted 08 July 2007 - 02:18 PM

I fixed the headers, switch-statements, returns and that. I did keep my <iostream> instead of <cstdio> and <cstdlib> after getting a Segmentation fault from trying to use a string in a printf() function...

However, after spending many hours lately trying to figure out how to use the input-validating code you provided, I've only got it to compile twice - and that was after much editing and without calling the template function. I do get how the template function is supposed to work, but I've reached the end of my debug-unknown-code-skills. I just can't get rid of my last error. I've simply decided to let it be for now, until I've learned more and can fix it. :)
  • 0





Also tagged with one or more of these keywords: user input

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download