There are a couple of issues. If using scanf
check its return. In addition to the numeric validity checks, you also have the issue of needing to flush the input buffer in the event something other than an integer is entered by the user. While there are several ways to do this, one way keeping with your approach would simply be to preform the checks you are doing, then manually flush the input buffer with a second do/while
loop. You can also turn your logic around and test for any one of the conditions being true forcing another prompt for the date. As noted there are many ways to approach this. Consider this as one among the other answers you receive.
int c = 0; /* value to test for end of input buffer */
printf("\nEnter the date of birth(mm/dd/yyyy):");
while ((scanf("%d/%d/%d",&add.dob.month,&add.dob.day,&add.dob.year) != 3) ||
(add.dob.month < 1) ||
(add.dob.month > 12 ) ||
(add.dob.day < 1 ) ||
(add.dob.day > 31) ||
(add.dob.year < 1) ||
(add.dob.year > 2015))
{
printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
do { c = getchar(); } while (c != '\n' && c != EOF); /* flush input buffer */
}
As mentioned a slightly more robust way to read the information from stdin
would be to read the date as a character string into a buffer using fgets
or getline
and then to parse the month, day, year information from the buffer. This can be done in many ways as well. Since you will ultimately be converting from character to decimal, you may as well just use strtol
to parse and convert rather then either stepping down the string with a pointer or parsing with strtok
or strsep
(as each would require conversion to decimal after separation anyway). This is a quick example that provides a fairly robust solution. It also allows dates to be entered as mm-dd-yyyy
or mm.dd.yyy
in addition to mm/dd/yyyy
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#define SZDATE 12
int main (void) {
int mm = 0; // month/day/year values
int dd = 0;
int yyyy = 0;
int gooddate = 0; // flag signifying valid date
char datestr[SZDATE] = {0}; // buffer to hold input string
char *p = NULL; // pointer to use with strtol
char *endptr = NULL; // end pointer for strtol
long val = 0; // long value for strtol
while (gooddate == 0)
{
printf("\nEnter the date of birth (mm/dd/yyyy): ");
/* read string with fgets */
fgets (datestr, SZDATE-1, stdin);
/* test sufficient length */
if (strlen (datestr) < 8) {
printf ("\n insufficient date length entered, try again.\n");
continue;
}
/* parse month value with strtol (with error checking) */
errno = 0;
val = strtol (datestr, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == datestr)
|| (*endptr != '/' && *endptr != '-' && *endptr != '.')
|| (val < 1)
|| (val > 12)) {
printf ("\n invalid month entered, try again.\n");
continue;
}
mm = (int) val; /* set month on successful conversion */
p = ++endptr; /* set p to start of day, reset endptr */
endptr = NULL;
/* parse day value with strtol (with error checking) */
errno = 0;
val = strtol (p, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == p)
|| (*endptr != '/' && *endptr != '-' && *endptr != '.')
|| (val < 1)
|| (val > 31)) {
printf ("\n invalid day entered, try again.\n");
continue;
}
dd = (int) val; /* set day on successful conversion */
p = ++endptr; /* set p to start of year, reset endptr */
endptr = NULL;
/* parse year value with strtol (with error checking) */
errno = 0;
val = strtol (p, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == p)
|| (*endptr != '\n' && *endptr != 0)
|| (val < 1900)
|| (val > 2015)) {
printf ("\n invalid year entered, try again.\n");
continue;
}
yyyy = (int) val; /* set year on successful conversion */
gooddate = 1; /* set gooddate flag ending loop */
}
printf ("\n valid date is: %d/%d/%d\n\n", mm, dd, yyyy);
return 0;
}
Think through the checks associated with the strtol
conversions. You may have more you would like to add. Also, try the parsing with strtok
or the like and compare. This is just one way of approaching reading as a string and then parsing. It can be done many different ways.