0

Take a look a this piece of code, which is supposed to get the date of birth of a user, in the form of three variables belonging to a struct.

printf("Insert date of birth in this format: dd/mm/yyyy\n");
scanf("%d/%d/%d", &user.bDay, &user.bMonth, &user.bYear);

while(isalpha(user.bDay)==1||isalpha(user.bMonth)==1||isalpha(user.bYear)==1){
    puts("Invalid input");
    scanf("%d/%d/%d", &user.bDay, &user.bMonth, &user.bYear);
}

What if the user types characters? Something like 1q/02/199i? I wanted to make the program print an error message and simply asking the user to insert his date of birth again. I tried using isalpha function, as you can see in the code, but it doesn't work, the program crashes and prints "Invalis input" infinite times. How can I make the user insert only integers?

Tiziano666
  • 21
  • 5
  • Check the return value of `scanf`. – kaylum Jul 05 '21 at 11:04
  • 1
    It doesn't make sense to use `isalpha(user.bDay)` etc. because these values should be of type `int` (to match the format `%d`) and are either the result of the conversion by `scanf` (if successful) or unmodified (if unsuccessful). One option to check for valid input would be to read the whole line as a string with `fgets` and check for valid input before converting the values with `sscanf`. Of course there are different ways to implement this. In general, `scanf` should not be used for user input that must be checked, but only for input that is guaranteed to have a specific format. – Bodo Jul 05 '21 at 11:04

2 Answers2

0

scanf is scanning the input string for integers. Considering that, I suppose that your struct is a struct of int, or uint16_t, or something of the sort.

In any case, 'checking' these integers with isalpha, as if they were characters, is not going to help you. Just a small example: if the user had written '9' (which is 57 in ASCII), scanf will convert this to 9. 9 ASCII is not a digit, nor an alphanumeric character.

Also, to confirm that you have a digit, you want to check it with isdigit. Using isalpha to see that it is not a digit, is insufficient; the user might have entered a symbol of some kind, which is neither an alphabetic character nor a numeric digit.

However, these checks must be done on the character the user entered. They can not be done on the integer variables filled in by scanf.

If you read the user input as a string, you can parse it yourself and do whatever validation you would like (for example, use strtok to split it at the slashes, and then use isdigit on each character in each token).

Alternately, you can use scanf, and then check your three integers, that they are each in the expected range (1-31 for day, 1-12 for month, etc.).

Or, you can do away with the formatted string, and separately ask the user for day, month, and year, validating each one separately.

Basya
  • 1,477
  • 1
  • 12
  • 22
0

How to stop user from inserting characters instead of integers

Read the line of user input into a string with fgets().
scanf() is difficult to use with good error handling.

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin)) {

Then test the string's validity:

  if (sscanf(buffer, "%d /%d /%d", &user.bDay, &user.bMonth, &user.bYear) == 3) {
    Success();
  }
  else {
    puts("Invalid input");
  }
}

Add additional tests as desired like range limits and a test for trailing junk.

  char junk;
  if (sscanf(buffer, "%2d /%2d /%4d %c", &user.bDay, &user.bMonth, &user.bYear, &junk) == 3
      && user.bDay >= 1 && user.bMonth >= 1 && user.bMonth <= 12 /* ... */) {
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256