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 ZipOnTrousers

ZipOnTrousers

    CC Resident

  • Validating
  • PipPipPipPip
  • 91 posts

Posted 28 December 2010 - 08:41 PM

Hi guys, I'm writing a little random number guessing game as a little project and I've only just realised how difficult it can be to validate user input in c... too used to Java and python where its (relatively) easier. So I wanted to write the guessing game so that the user could only enter a valid and relevant number, between 0 and 100. I have the below code and its working almost perfect:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>

typedef enum boolean {BFALSE, BTRUE} bool_t;

void die (char *msg)
/* This method takes a char array (string) as parameter and prints this as error message on failure, then exits  */

{
	fprintf (stderr, "%s\n", msg);
	exit (EXIT_FAILURE);
}

bool_t get_int (int *ival)
{
	char buff[5];
	long lval;
	char *end;
	
	if (fgets (buff, sizeof buff, stdin) == NULL)
		return BFALSE;
	
	lval = strtol (buff, &end, 10);
	
	if (lval < INT_MIN || INT_MAX < lval || end == buff)
		return BFALSE;
	
	*ival = (int)lval;
	
	return BTRUE;
}

int main (int argc, const char * argv[]) {
	int ranNum = 0, userGuess =0;
        // generate ranNum (based on time)
	srand(time (NULL));
	ranNum = (rand() % 100);
	
	printf("I have just generated a random number between 0 and 100. Can you guess it?\n\n");

	while (ranNum != userGuess) {
		// Validate input - if not a number between 0 and 100 then exit
		if (get_int (&userGuess) != BFALSE && userGuess <= 100 && userGuess >= 0)
			printf ("Your number was: %d\n", userGuess);
		else {
			die ("Invalid integer");
		}
	
		if (userGuess > ranNum) {
			printf("Wrong! Too high!\n");
			printf("Guess again:");
		}
		else if (userGuess < ranNum) {
			printf("Wrong! Too low!\n");
			printf("Guess again:");
		}
	}
	
	//If all conditions met so far, numbers must match so print success and exit
	printf("Well done! You guessed it! (Eventually...)\n");

	return 0;
}

/* End of main.c */

I just wanted to know if you guys think this is the safest way of validating user input like this? It seems an awful convoluted way of doing it as it uses two additional functions just to safely check if input is an integer... but I've heard terrible things about scanf and obviously gets is a no-go. Any opinions?

Also, I wanted to have the game continue to loop after informing the user of the invalid input... though I can't see any way of doing this that won't make the code much more complicated. If anyone has any ideas on how to improve I'd really appreciate it. (I realise this is probably not the best way to generate a random number, I just used it so it generated something. Sure there are much better ways but meh, this works as well.)

Thanks
ZipOn
  • 0

#2 Alexander

Alexander

    YOL9

  • Moderator
  • 3963 posts
  • Location:Vancouver, Eh! Cleverness: 200
  • Programming Language:C, C++, PHP, Assembly

Posted 28 December 2010 - 10:20 PM

Hi,

fgets returns unformatted string, so scanf can be used for this purpose. scanf is only dangerous when misused (such as %s specifier), you can verify buffered input as so:
int integer = 0;
  char line[255];
  if ( fgets ( line, sizeof line, stdin ) == NULL
    || sscanf ( line, "%d", &integer ) != 1 )
  {
    /* Error handling here, continue loop */
  } else {
     break;
  }
Remember scanf returns the number of successfully scanned elements, therefor if only an integer exists in input than it will return 1.

You can go further with scanf and verify exact input, although this is extra and not required by your simple verification purposes:
int integer;
char character;
if(scanf("%d%c", &integer, &character) != 2 || character != '\n') {
    /* Not an integer, continue loop */
} else {
    break;
}

  • 0

All new problems require investigation, and so if errors are problems, try to learn as much as you can and report back.


#3 TC_EX

TC_EX

    CC Lurker

  • Just Joined
  • Pip
  • 1 posts

Posted 28 December 2010 - 10:58 PM

Try this on for size. You needn't use enter when entering double digits and if you want to report an error, fine, but app will ignore non-digits.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctype.h>
#include <time.h>

int ReadInput () {
	char Entry [16];
  int Numb, Pos = 0, Ch;

	while ((Ch = getch ()) != 13) {
		if (Ch < '0' || Ch > '9')
			continue;

		putch (Ch);
		Entry [Pos++] = Ch;
		if (Pos == 2)
			break;
		}

	Entry [Pos] = NULL;
	return atoi(Entry);
	}

int main (int argc, const char * argv[]) {
	int ranNum, UserGuess, Guesses = 0;
  char choice = 'N';

	do {
		Guesses = 0;
		srand (time (NULL));
		ranNum = rand () % 100;

		printf ("\n\nHi/Low Game\n\n\n\n");

		do {
			printf ("%d ", ++Guesses);
			UserGuess = ReadInput ();
			printf ("    ->");

			if (UserGuess == ranNum)
				break;

			if (UserGuess < ranNum)
				printf ("LOW");
			else
				printf ("HIGH");

			printf ("\n");

			} while (1);

		printf ("\n\nCongratulations  Play again? [Y/N]");
		choice = getch ();

		} while (choice == 'Y' || choice == 'y');


	return 0;
}

  • 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