Hey guys,
Im learning C online, and its hard somtimes to understand the concepts, w/o being in class asking questions. I was wondering hat would be the easiest and fstest way to understand numeric validating(no characters) and could anyone break it in easy steps? im new, but really excited about C and will learn fast. I found this program in one of the books, but it doesnt really explain whats going on under the hood, if there is an easier way of doing it please let me know.
I dont understand things, that happens in the loop.,
Cheers, and thanx a lot for your time!!! )

#include<stdio.h>

int get_int(void);

main()

{

printf ("Enter an integer:");

get_int();

printf ("Good!\n");

}

int get_int(void)

{

int input;
char ch;

    while (scanf("%d", &input) != 1)

    {

        while ((ch = getchar()) != '\n')

            putchar(ch);  // dispose of bad input

        printf(" is not an integer.\nPlease enter an ");

        printf("integer value, such as 25, -178, or 3: ");

    }

    return input;

}

Dani AI

Generated

Quick practical notes for , with pointers to the replies from , , and .

The original loop uses scanf and a small inner loop to discard the rest of a bad line; as and noted, scanf returns how many items it successfully read and the program keeps asking until it gets one. The main weakness — which and also point out — is that relying on formatted input alone makes it hard to detect overflow, trailing characters, or partial input, so a safer pattern is: read one whole line, then parse and validate that string.

A compact, practical implementation uses fgets to read a line and strtoimax to convert while checking errno and the end pointer. It lets you detect "no digits", "trailing junk", "value out of range", and overly long lines, and keeps the input logic simple and testable:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <string.h>

int get_int(void) {
    char buf[128], *end;
    while (fgets(buf, sizeof buf, stdin)) {
        if (!strchr(buf, '\n')) {           /* line too long */
            int c; while ((c = getchar()) != '\n' && c != EOF) ;
            puts("Input too long");
            continue;
        }
        errno = 0;
        intmax_t v = strtoimax(buf, &end, 10);
        if (end == buf) { puts("Not a number"); continue; }
        while (isspace((unsigned char)*end)) end++;
        if (*end != '\0') { puts("Trailing characters"); continue; }
        if (errno == ERANGE || v < INT_MIN || v > INT_MAX) { puts("Out of range"); continue; }
        return (int)v;
    }
    return 0; /* handle EOF as appropriate */
}

Notes and troubleshooting:

  • Always check fgets return value (EOF handling).
  • strtoimax is C99; use it when available for robust overflow detection. See its reference: strtoimax - cppreference.
  • If you need dynamic line lengths, prefer getline() where available or loop to discard the rest of an overlong line.
  • Avoid mixing scanf and line-based input in the same program — pick one consistent method.

Recommended Answers

All 5 Replies

#include<stdio.h> // include header

int get_int(void); // Function prototype is to be declared as the function is defined after main()

main() // Change to int main()

{

printf ("Enter an integer:");

get_int(); // Call function. No error as the function was declared previously

printf ("Good!\n");

}

int get_int(void)

{

int input;
char ch;

    while (scanf("%d", &input) != 1) // scanf returns the no of items successfully read. If user inputs a character then it won't be read into 'input' and scanf returns 0.

    {

        while ((ch = getchar()) != '\n') // Get all the characters given by the user (that is till '\n' was entered) then use putchar() to print it on the screen

            putchar(ch);  // dispose of bad input

        printf(" is not an integer.\nPlease enter an ");

        printf("integer value, such as 25, -178, or 3: "); // go back to the while loop where scanf will take the input from the user again 

    }

    return input;

}

it doesnt really explain whats going on under the hood

Ok, it's a simple but not a strong validation. For example, in most of C implementations scanf can't detect integer overflow (it's possible to type a huge number and to get some wrong number with scanf(...) == 1).
More strong (but not ideal) method is (an example only):

#include <limits.h>
#include <float.h>
...
int input;
double x;
...
if (scanf("%f",&x) == 1 && modf(x,&x) == 0.0 
    && x <= (double)INT_MAX && x >= (double)INT_MIN) {
    /* OK */
    input = x;
} else {
    /* not-a-number or integer overflow */
}

>More strong (but not ideal) method is (an example only)
Only an example because by the time you test for overflow, the damage is already done. Keep in mind that once you invoke undefined behavior, the rest of the program is undefined. You need to test before the damage is done either with a library function that's smarter (such as ) or by doing it all manually (which I don't recommend unless you know what you're doing):

#include <ctype.h>
#include <errno.h>
#include <limits.h>

const char *parse_int ( const char *s, int *value )
{
  /* Base of the final converted value */
  const unsigned base = 10;

  /* Largest possible value without the least significant digit */
  const unsigned limit = UINT_MAX / base;

  /* Least significant digit from the largest possible value */
  const unsigned top_digit = UINT_MAX % base;

  unsigned overflow = 0; /* True if integer overflow occurs */
  unsigned sign = 0;     /* Final sign of the converted value */

  unsigned temp = 0;     /* The intermediate converted value */
  unsigned n = 0;        /* Count of converted digits */

  /* Save and skip over the sign if present */
  if ( *s == '-' || *s == '+' )
    sign = *s++ == '-';

  /* Build the intermediate value */
  for ( ; isdigit ( *s ); s++, n++ ) {
    unsigned digit = *s - '0';
    
    /*
      This protects *only* the intermediate value
      from overflow. Overflow of the final value
      requires further checks
    */
    overflow =  temp > limit
      || ( temp == limit && digit > top_digit );

    if ( overflow )
      break;

    /* Shift-add by the base */
    temp = temp * base + digit;
  }

  if ( n > 0 ) {
    /*
      A conversion was made, so now we need to
      deal with overflow and set the final value
    */
    if ( overflow
      || ( sign && temp > -INT_MIN )
      || ( !sign && temp > INT_MAX ) )
    {
      /*
        The intermediate actually overflowed,
        or converting it to int would overflow.
        Either way it's an error to the caller
      */
      errno = ERANGE;
      temp = sign ? -INT_MIN : INT_MAX;
    }

    *value = sign ? -(int)temp : (int)temp;
  }
  else if ( sign ) {
    /*
      We found a sign and skipped over it. But
      because no conversion was made, we need
      to "unskip" the sign
    */
    --s;
  }

  return s;
}

#include <stdio.h>
#include <string.h>

int main ( void )
{
  char buffer[20];

  while ( fgets ( buffer, sizeof buffer, stdin ) != NULL ) {
    int x;
    const char *p;

    buffer[strcspn ( buffer, "\n" )] = '\0';
    
    errno = 0;
    p = parse_int ( buffer, &x );

    if ( errno != 0 )
      puts ( "Overflow!" );

    if ( *p == '\0' )
      puts ( "Successful conversion!" );
    else
      printf ( "Unconverted: \"%s\"\n", p );

    if ( p != buffer )
      printf ( "Value = %d\n", x );
    else
      puts ( "No value found" );
  }

  return 0;
}

Notice that both of these solutions rely on unformatted input using fgets and then a more precise validation of the string in memory. It's much easier to validate your input without having to worry about mucking with the stream at the same time.

>by the time you test for overflow, the damage is already done
No any damage (in 32-bit environment ;) ) at this moment because an example code tests possible integer (not double) overflow (compare int and IEEE double ranges). More robust test requires _finite call to detect possible double under/overflow:

#include <limits.h>
#include <float.h>
... // For 32-bit int type only?
int input;
double x;
... // must be %lf, sorry...
if (scanf("%lf",&x) == 1 && _finite(x) && modf(x,&x) == 0.0 
    && x <= (double)INT_MAX && x >= (double)INT_MIN) {
    /* OK */
    input = x;
} else {
    /* not-a-number or integer overflow */
}

Of course, strtol+errno check looks better (simpler) but strtol requires int representation buffering.

the program u wrote checks whether the entered input is an integer or character
if it is an inter it returns "good".
Basically you are using the
"int get_int(void)"
to call a function to perform your task.

while (scanf("%d", &input) != 1)

    {

        while ((ch = getchar()) != '\n')

            putchar(ch);  // dispose of bad input

        printf(" is not an integer.\nPlease enter an ");

        printf("integer value, such as 25, -178, or 3: ");

    }

    return input;

the above part of the program is as:

1.the program continues ubtil u enter 1
2.if u enter any character or string your last character is always "\n" that is automatically added in the last of the string u write.
so the program continues until the end if the string
3.when while loop continues it prints the character u entered in the string since putchar is used to print the char on the output screen.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.