Jump to content

[C] Validating user input...

- - - - -

  • Please log in to reply
2 replies to this topic

#1
ZipOnTrousers

ZipOnTrousers

    Learning Programmer

  • Validating
  • PipPipPip
  • 94 posts
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

#2
Alexander

Alexander

    It's Science!

  • Moderators
  • 4,118 posts
  • Location:Vancouver, Eh! Cleverness: 200
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;
}

Be sure to read the updated FAQ! || Health is achieved through the same 10,000 steps.
If a suggested code/method fails, informing us is less important than telling us why or what errors occurred.

#3
TC_EX

TC_EX

    Newbie

  • Members
  • Pip
  • 1 posts
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;

}






1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users