Excluding certain characters

Hello! I would like to know if there's a way to exclude any characters (eg letters, symbols) so a user can only enter number in this case because they are supposed to enter the year. i would like to do this because if the user enters anything that isn't a number, the loop will keep looping.
1
2
3
4
5
6
7
8
9
10
11
   do {
        printf("\n Enter your birth year : ");
        scanf("%d", &birth_year);
        {
            if (birth_year <= 2019) {
                printf("Age : %d ", 2019 - birth_year);
            }
            else
                printf("Invalid number (No more than 2019)\n");
        }
    } while (birth_year >= 2019);
Last edited on
Why do your printf's have all of those spaces?
@dutch its to center it in the output (cmd)
Any help?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>

void ignore_rest_of_line()
{
    char ch;
    while ( scanf( "%c", &ch ) == 1 && ch != '\n' ) ;
}

int get_int( const char *prompt, int minv, int maxv )
{
    printf( "%s? an integer in [%d,%d], immediately followed by a new line: ",
            prompt, minv, maxv ) ;

    int number ;
    char nextc ;
    int result = scanf( "%d%c", &number, &nextc ) ;
    if( result == 2 && nextc == '\n' )
    {
        if( number < minv ) printf( "the value %d is too small. try again\n", number ) ;
        else if( number > maxv ) printf( "the value %d is too large. try again\n", number ) ;
        else return number ; // valid input,; return it
    }

    // else if( result == EOF ) { /* input failure on stdin */ }

    else
    {
        puts( "invalid input. try again." ) ;
        ignore_rest_of_line() ;
    }

    return get_int( prompt, minv, maxv ) ; // try again
}

int main()
{
    const int year = get_int( "year of your birth", 1900, 2019 ) ;
    printf( "the year of your birth is %d\n", year ) ;
}
@JLBorges, is there a way that i could do the same thing but simpler (I have not reached that level of c programming yet so I don't know how to use the code above well)
By the time you've coded around scanf leaving the input stream in an undefined state, you may as well have used fgets.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
char buff[BUFSIZ];
if ( fgets(buff,sizeof(buff),stdin) ) {
    if ( sscanf(buff,"%d",&number) == 1 ) {  // strtol would be better.
        if ( number >= min && number <= max ) {
            // success
        } else {
            // out of range
        }
    } else {
        // Not a number
    }
} else {
    // input error or end of file.
    // Usually, EOF by the user pressing ctrl-d or ctrl-z
    // Use feof() and ferror() if necessary.
}


You can put that in a loop to repeat as necessary.


> return get_int( prompt, minv, maxv ) ; // try again
Ugh.
Recursion to implement a loop.
Better hope they give up before the stack blows.
Last edited on
I continue to be of the opinion, and loudly so, that you should

First get user input as a string, by line, then try to convert it to the desired type.

This is because the user will always press Enter at the end of every input.

C is not the most friendly when it comes to getting a line of input from the user. I typically write a simple function to help.

Also, one of the problems with C is that it presupposes a lot of correctness in input, leading to undefined behavior if input is not first carefully checked. As a result, it is worth writing a few routines to do things for you do things, like convert to int.

Here is a simple example. Notice that, while the addition of a couple of routines seems to complicate things, it actually makes life easier where it counts: check out main().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <ctype.h>
#include <errno.h>
#include <iso646.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//-------------------------------------------------------------------
// Extract a line of text (including the newline) from f
// Store the first n characters in s
// Returns success or failure
//
bool getline( FILE* f, char* s, int n )
{
  char* p;

  // Get a line of text, maximum n-1 characters
  *s = '\0';
  if (!fgets( s, n, f )) return false;

  // Remove the newline from the text
  p = strchr( s, '\n' );
  if (p)
  {
    *p = '\0';
  }
  // Or extract and discard characters until newline (inclusive)
  else while (true)
  {
    char c = fgetc( f );
    if ((c == '\n') or (c < 0)) break;
  }

  return true;
}

//-------------------------------------------------------------------
// Convert a string to an int
// The string may have leading and trailing whitespace, but must
// otherwise contain only an integer value, radix = 10.
// Returns success or failure
//
bool string_to_int( const char* s, int* n )
{
  char* endptr;
  long int v;

  // Skip leading whitespace
  while (isspace( *s )) s++;

  // Attempt the conversion
  errno = 0;
  v = strtol( s, &endptr, 10 );
  if (errno or (!v and (endptr == s))) return false;

  // Skip trailing whitespace / fail if anything but whitespace
  while (isspace( *endptr )) endptr++;
  if (*endptr) return false;

  // Return the converted value
  *n = v;
  return true;
}

//-------------------------------------------------------------------
int main()
{
  // We will reuse this over and over...
  char s[ 1000 ];
  
  // An integer value we want to get from the user
  int age;
  {
    printf( "age? " );
    fflush( stdout );
    getline( stdin, s, sizeof(s) );
    if (!string_to_int( s, &age ) || (age < 0))
    {
      fprintf( stderr, "That was not a valid age!\n" );
      return 1;
    }
  }

  printf( "Good job! Age = %d\n", age );
}

Hope this helps.
@Salem c, how do you exclude numbers? In ur code it said “not a number”
@nickname687
Typing in say
123abc
would result in a successful sscanf, and you would get 123 stored in number for you to test at line 4.

Typing in say
abc123
lands you at line 10, because the sscanf failed immediately.

sscanf doesn't care about trailing junk. If it manages to start a conversion, then the conversion will be successful.

But the point is, the "abc" is now in memory, regardless of whether the conversion was successful or not. So you don't have to do any of that 'conversion failed, so read until \n' logic.


Normally perhaps, you would use this to keep reading lines until you determined some kind of success.
1
2
3
4
5
while ( fgets(buff,sizeof(buff),stdin) ) {
    // do your thing with a line
    // if that is successful, then 
    break;
}


Topic archived. No new replies allowed.