Closed Thread
Results 1 to 3 of 3

Thread: [C++] Validating user input

  1. #1
    Xochiquetzal is offline Newbie
    Join Date
    Jun 2007
    Posts
    5
    Rep Power
    0

    [C++] Validating user input

    '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.

    Code:
    #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;
    }

  2. CODECALL Circuit advertisement
    Join Date
    Always
    Posts
    Many

     
  3. #2
    v0id is offline Retired
    Join Date
    Apr 2007
    Posts
    2,937
    Blog Entries
    3
    Rep Power
    42
    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.
    Code:
    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.
    Code:
    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.
    Code:
    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.
    Code:
    #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.
    Code:
    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.

  4. #3
    Xochiquetzal is offline Newbie
    Join Date
    Jun 2007
    Posts
    5
    Rep Power
    0
    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.

Closed Thread

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Similar Threads

  1. Getting input from user
    By restin84 in forum Linux Programming and Scripting
    Replies: 3
    Last Post: 10-04-2011, 05:35 AM
  2. Validating Input
    By NorCalAirman in forum C and C++
    Replies: 7
    Last Post: 05-18-2011, 05:29 PM
  3. [C] Validating user input...
    By ZipOnTrousers in forum C and C++
    Replies: 2
    Last Post: 12-28-2010, 10:58 PM
  4. NASM User input help 2
    By untitled_1 in forum Assembly
    Replies: 3
    Last Post: 11-07-2010, 12:46 AM
  5. Need Help: Trivia Program using Menus and Validating Input
    By Nollen in forum Visual Basic Programming
    Replies: 3
    Last Post: 11-01-2007, 11:13 AM

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts