hey!
I'm working on a program that part of it asks for an integer input.
then if the value entered is not an integer, it should print an error message. If not, then the rest
of program (which I've got partly complete).
But, I have no idea how to distinguish between an integer and a non-integer value.
I have nothing to post here for that part,cuz i don't know where to start.
the only thing that came to my mind ( and did not work), was the max value for an integer and float, but it turned out to be crap!
any help is appreciated.

If you're using scanf, you can just test the return value. It returns the number of items that were successfully converted:

int x;

if ( scanf ( "%d", &x ) != 1 )
  fprintf ( stderr, "Invalid input\n" );

The format string only has one specifier (%d), so if the call succeeds completely, it should return 1. Anything else is an error.

here's the whole testdrive which I'm working on:

#include <stdio.h>
#include<stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include<ctype.h>

// Constants for TTT game board symbols.
#define EMPTY  ' '
#define USER 'O'
#define COMPUTER 'X'

 
// function proto-types (these are function declarations).
// Value returning funcitons tested by the automated driver.
bool ValueInRange(int value, int min, int max);
bool RowIsWinner(char s1, char s2, char s3);
char TTTopponent(char player);

// I/O functions -- manually tested.
int  GetIntInput(int min, int max);
void DisplayHorizontalLine();
void DisplayOneRow(char s1, char s2, char s3);

// Utility functions used by the automated test driver:
//bool UserSaysYes(string question);
void Report(int, bool, char[]);
void DisplayTTTBoards();
bool UserSaysYes(char[]);
char getCharInput();
void clearInputStream();




//*****************************************************
//*****************************************************
//****  Test driver / Test oracle for functions *******
//****	DO NOT CHANGE THE CODE IN THE MAIN FUNCTION!!!**
//*****************************************************
//*****************************************************
int main()
{
	// Test oracle:  this portion will run some automated tests and report the results.
	// Automated tests for ValueInRange()

	printf("\n Running test oracle for ValueInRange() function...\n");
	printf( "These test cases should return true...\n");
	Report(1,   ValueInRange(5,1,10),		"ValueInRange(5,1,10)");
	Report(2,   ValueInRange(1,1,1),		"ValueInRange(1,1,1)");
	printf( "These test cases should return false...\n" );
	Report(3, ! ValueInRange(-1,1,10),		"ValueInRange(-1,1,10)");
	Report(4, ! ValueInRange(101,-100,100),	"ValueInRange(101,-100,100)");

	// Automated tests for RowIsWinner()

	printf("\n Running test oracle for RowIsWinner() function...\n" );
	printf( "These test cases should return true...\n");
	Report(1,   RowIsWinner('X', 'X', 'X'), "RowIsWinner('X', 'X', 'X')");
	Report(2,   RowIsWinner('a', 'a', 'a'), "RowIsWinner('a', 'a', 'a')");
	printf( "These test cases should return false...\n"); 
	Report(3, !RowIsWinner(' ', 'X', 'O'), "RowIsWinner(' ', 'X', 'O')");
	Report(4, !RowIsWinner(' ', ' ', ' '), "RowIsWinner(' ', ' ', ' ')");


	printf( "\n Running test oracle for TTTopponent() function...\n");	
	Report(1, TTTopponent(COMPUTER) == USER, "TTTopponent(COMPUTER) should return USER");
	Report(2, TTTopponent(USER) == COMPUTER, "TTTopponent(USER) should return COMPUTER");

	// Interactive Test driver:  this portion will allow you to run some custom tests.
	int val, min, max;
	char s1, s2, s3;


	printf( "\n Ready to run interactive tests...\n\n");
	while ( UserSaysYes("Do you want to run another test?") )
	{
		printf( "Testing GetIntInput() function...\n");
		printf("Enter a minimum bound (any integer):");
		min = GetIntInput(INT_MIN, INT_MAX);
		printf("Enter a maximum bound (must be >= %d )", min);
		max = GetIntInput(min, INT_MAX);
        printf( "Enter a value between %d and %d ", min ,max);
		val = GetIntInput(min, max);
		printf( "ValueInRange(%d, %d, %d) returned %s \n", val, min ,max,
        (ValueInRange(val,min,max)?"true":"false"));

		
		printf( "\n\n Enter values(characters) for three squares from a TTT board:\n ");
		s1 = getCharInput();
		s2= getCharInput();
		s3 = getCharInput();
	
		printf( "That would %s be considered a winning TTT row\n", (RowIsWinner(s1, s2, s3)?" ":" NOT "));
		

	}


	printf( "Testing functions to display TTT board...\n" );
	DisplayTTTBoards();
	
	system("PAUSE");
	
	return 0;
}






//*****************************************************
//*** Function stubs are provide below for the six  ***
//*** functions that you need to write.             ***
//*****************************************************

// This function determines if a value is within a range.
// PRE: min <= max and value is defined
// POST: returns true if min <= value <= max, and false otherwise.     
bool ValueInRange(int val, int min, int max)
{
	return( val>= min && val<= max);
}

// This function determines if a row of tic-tac-toe squares is a winning row.
// PRE: s1, s2, and s3 are defined
// POST: returns true if a row (horizontal, vertical, or diagonal) on
//		 a tic-tac-toe board containing [s1, s2, s3],
//		 is a winning row, and false otherwise.     
bool RowIsWinner(char s1, char s2, char s3)
{
	// Your code goes here
	// Note: this function may assume that an empty square 
	//		 contains the value EMPTY, but should make no assumptions 
	//		 about how the other game pieces (X's and O's) are represented!
	return (s1==s2 && s2==s3 && s3!= EMPTY);
}

// This function returns the opponent of the player.
// PRE: player == COMPUTER or player = USER
// POST: returns the opponent of player.     
char TTTopponent(char player)
{
	// Your code goes here
	if(player == COMPUTER)
        {
           return USER;
        }
    else
     	{
           return COMPUTER;	// dummy return value -- delete this.
        }
	}
     
int  GetIntInput(int min, int max)
{
	// Your code goes here
	// Note: you should call your ValueInRange function to validate the user's input!
	//		 This function must also check that the user enters integer data,
	//		 and issue an error message and re-prompt the user if they make a mistake.
    int val;
    printf("Please enter an integer:\n");
	if (val!= // if it's not an integer )
	  {
              printf ( "Invalid input! Please enter your value again:\n" );
              scanf ("%i", &val);
      } 
    else
          {  
             if(ValueInRange( val, min, max))
                  {
                     return val;
                  }
             else
                  {
                     printf("This number is not in range!\n"); 
                  }
          }      
       
         
  
return(0);
}

// This function displays one row of a TTT board with squares s1, s2 and s3
// PRE: the cout output marker is at the start of a new line.
// POST: A row of the TTT board is drawn on the cout stream.     
void DisplayHorizontalLine()
{
	printf("\n---+---+---\n");
	
}

void DisplayOneRow(char s1, char s2, char s3)
{
	 printf("%c | %c | %c\n" , s1, s2, s3);// Your code goes here
}

// Below are the helper functions for test driver. DO NOT CHANGE!!!

// PRE: none
// POST: a message indicating results of test has been displayed
void Report(int testNumber, bool testSuccess, char testCase[])
{
	if (testSuccess)
		printf( "\t %c   %c    %c CORRECT ", char(2),char(1),char(2));
	else
		printf( "\tX  INCORRECT ");

	printf( "result produced by test # %d \n", testNumber);

	if (! testSuccess)
		printf( "\t\tTest case was :%s \n" ,testCase );
}

// This function prompts the user with a yes/no question and returns their answer.
// PRE:	 question is a yes/no question the user should answer
// POST: returns true if user answered YES, false if they answer NO
bool UserSaysYes(char question[])
{
	char answer;
	do {
		printf("%s (Y/N):",question);
       
		answer= getCharInput();
		answer = toupper(answer);

	} while (!(answer == 'Y' || answer == 'N'));
    clearInputStream();
	// INV: answer == 'Y' || answer == 'N'

	printf(" \n\n");
	return (answer == 'Y');
}

// This function uses the two output functions display a few of TTT boards
// PRE: none.
// POST: three TTT boards have been drawn on the output stream.     
void DisplayTTTBoards()
{
	printf( "An empty TTT board should be drawn below:\n\n");
	DisplayOneRow(' ',' ',' ');
	DisplayHorizontalLine();
	DisplayOneRow(' ',' ',' ');
	DisplayHorizontalLine();
	DisplayOneRow(' ',' ',' ');

	printf("\nA TTT board in play should be drawn below:\n\n");
	DisplayOneRow(COMPUTER,' ',COMPUTER);
	DisplayHorizontalLine();
	DisplayOneRow(' ',USER,USER);
	DisplayHorizontalLine();
	DisplayOneRow(USER,COMPUTER,' ');

	printf("\nA numbered TTT board in play should be drawn below:\n");
	DisplayOneRow('0','1','2');
	DisplayHorizontalLine();
	DisplayOneRow('3','4','5');
	DisplayHorizontalLine();
	DisplayOneRow('6','7','8');

}

//This function clears the newline characters('\n') from the input stream
//and reads the first non-newline character
//Pre: None
//Post: The first non-newline character is returned.
char getCharInput()
{
     char input;
     input  = getchar();
     while(input=='\n')
     {
       input = getchar();
     }
     return input;
}
//This function clears everything left on the input stream until a newline 
//character is read
void clearInputStream()
{
     char input=getchar();
     while (input!='\n')
     {
           input = getchar();
     }
}

the part in red is where i'm stuck.
there are comments above it, and that's what i came up with.
when i call ValueInRange function in GetIntInput function, it does not work properly either.
when the value is not in range, it should print value is not in range( at least it's what i'm intended to do), but it doesn't.

it's driving me crazy.
Thanks for your help

Something like this, I suppose:

int GetIntInput(int min, int max)
{
  printf("Please enter an integer:\n");

  if (scanf ("%i", &val) != 1)
  {
    printf ( "Invalid input! Please enter your value again:\n" );
  }
  else
  {
    if(ValueInRange( val, min, max))
    {
      return val;
    }
    else
    {
      printf("This number is not in range!\n");
    }
  }

  return(0);
}

hey,
thanks for your help. Ireally appreciate it.
it's working, but partly!
when a non-integer value is entered, it gives me the error messege .
but doesn't let me to enter again, and continues itself.
I added another scanf("%i", &val); right after the printf("Invalid input! Please enter your value again:\n" ); , but it did not help.

int val;    
      if (scanf ("%i", &val) != 1)
   
      {
   
      printf ( "Invalid input! Please enter your value again:\n" );
      scanf ("%i", &val);
      }

any ideas?

why can i not use scanf?
I don't know how mygeti works.

and another thing.
when i the value is not in range, I get the error message, but i wanted it to stop after the error.
I used a break statement but it didn't work ( is break only allowed in loop and while?)

if(ValueInRange( val, min, max))
  
                  {
                        return val;
                  }
  
             else
                  {
                        printf("This number is not in range!\n");
                        break;
                  }

thanks for all your help.

my latest attempt:

if (scanf ("%i", &val) != 1)
   
         {
             printf ( "Invalid input! Please enter your value again:\n" );
             getchar();
             scanf("%i", &val); 
         }

still not workinng properly.
how can i get the user to enter a value again and then store it ?

why can i not use scanf?

my latest attempt:
still not workinng properly.
how can i get the user to enter a value again and then store it ?

Haven't you figure out yet why you should avoid using scanf?
Reading an integer from input requieres from you the programmer to know how it works.
Scanf stops reading any input if is not what you are asking for. Therefore if the user enters
the wrong input you need to clean the stdin buffer, because the inputted data is still there.
On top of that. Scanf leaves behind the "enter key", which most probably will mess you up
if you try to read again using another scanf.

FWIW:

/* skunk.c */
#include <stdio.h>

int main( void )
{
    int i = 0;
    char c = '\0';
    
    fputs( "Enter an integer: ", stdout );
    fflush( stdout );
    
    while( scanf( "%d%c", &i, &c ) != 2 )
    {
        while ( ( c = getchar() ) != '\n' && c != EOF );
        printf( "Invalid input! Please enter the value again: " );
        fflush( stdout );
    }
    printf( "i = %d\n", i );
    
    getchar();
    return 0;
}

>Haven't you figure out yet why you should avoid using scanf?
I don't think you should avoid scanf. I think you should learn how it works so that you can use it intelligently.

>Reading an integer from input requieres from you the programmer to know how it works.
Isn't that the case with everything? I mean, if you don't know how something works, how are you supposed to use it the right way?

>Therefore if the user enters the wrong input you need to
>clean the stdin buffer, because the inputted data is still there.
scanf is for formatted input. The problem is that it's hard to make people type the format you expect. That doesn't make scanf bad (you can always redirect stdin from a file or pipe), but it does make it easy to abuse. Worse, it does automatic conversions with a seemingly simple function call, so it's picked up by beginners and teachers who don't want to deal with teaching about string conversions first.

>Scanf leaves behind the "enter key", which most probably will
>mess you up if you try to read again using another scanf.
Another call to scanf will probably work just fine. scanf works well with itself, but not well with unformatted input functions. fgets, gets, and getchar are notorious for causing problems due to the leftover newline. You can break scanf too if you use one of the conversion specifiers that doesn't eat leading whitespace and don't realize that it doesn't.

The problem is that scanf is an advanced function that has subtle semantics, but teachers and beginners alike don't realize it. It also seems that there's a rampant lack of understanding about how I/O streams work, which just adds to the mystery of scanf.

>while( scanf( "%d%c", &i, &c ) != 2 )
There's really no point reading c here because the next thing you do is getchar into c.

>while ( ( c = getchar() ) != '\n' && c != EOF );
You have a little bug here. c is declared as char (which can be unsigned), but you try to test it against EOF (which is required to be negative).

>while( scanf( "%d%c", &i, &c ) != 2 )
There's really no point reading c here because the next thing you do is getchar into c.

>while ( ( c = getchar() ) != '\n' && c != EOF );
You have a little bug here. c is declared as char (which can be unsigned), but you try to test it against EOF (which is required to be negative).

I stand corrected.
Your comments are always appreciated. After all I don't know of any other efficient way of
learning except to listen to those that have learned already.

>Haven't you figure out yet why you should avoid using scanf?
I don't think you should avoid scanf. I think you should learn how it works so that you can use it intelligently.

I disagree. You have to have all kinds of special code to get scanf() to work properly. It's different for ints, char*, and single chars (which is a total waste IMAO). See this series.

>Reading an integer from input requieres from you the programmer to know how it works.
Isn't that the case with everything? I mean, if you don't know how something works, how are you supposed to use it the right way?

You hit the problem right on the head. No one teaches the right way so everyone struggles and asks the same question program after program.


Best to switch to fgets() and be safe. Then for formatted input use sscanf() to break the input apart. But in your case, megan-smith, you need to look at the input and check if there are illegal characters before using sscanf(). That way if someone enters 23x the input fails as it should.

This article has been dead for over six months. Start a new discussion instead.