brian.schiller.uml
brian.schiller.uml

Reputation: 87

Problems when using scanf with %i to capture date (mm dd yyyy)

I'm writing a program that calculates the number of elapsed days between two dates. To do this, I have to input the dates as integers in a structure defined like so:

struct date {
    int month;
    int day;
    int year;
};

Now, I've figured out how to run my program, but it's really bugging me that the user can't input a date in (mm dd yyyy) format when the month or day are single digits. Let me show you my code (please don't mind the debug printf statements):

printf("Enter your start date (mm dd yyyy)\n");
scanf("%i %i %i", &startDate.month, &startDate.day, &startDate.year);
// DEBUG printf("Start date = %i/%i/%i\n", startDate.month, startDate.day, startDate.year);
// DEBUG printf("start date month = %i", startDate.month);

printf("Enter your end date (mm dd yyyy)\n");
scanf("%i %i %i", &endDate.month, &endDate.day, &endDate.year);
// DEBUG printf("End date = %i/%i/%i\n", endDate.month, endDate.day, endDate.year);

If the user enters:

08 08 2004

Then the start date is recorded as

0/8/0

Which is equal to the first three digits entered by the user. OK, I understand that. I also understand that the user can just enter "8 8 2004" and the program runs fine...but I believe programming is about details and this one is a bugger. Can anyone help me fix this?

Upvotes: 3

Views: 3680

Answers (1)

jxh
jxh

Reputation: 70502

Using the %i conversion specifier causes scanf() to parse the input as if strtol() was called with 0 as the base argument. So, since 08 begins with a 0, and 8 is not an x or X, it treats the 08 as an octal sequence. But, since 8 is not a valid octal number, it stops there, and the result is 0 for the first number.

The second number then gets the 8, as it is delimited by whitespace. The white space is skipped, and the third number is parsing 08 as octal again, resulting in 0 for the third number. The remaining 8 and the year 2004 are not parsed.

Use %d to parse decimal digits.

scanf("%d %d %d", &startDate.month, &startDate.day, &startDate.year);

As mentioned in the comments, scanf() should generally be avoided. As an alternative, you could use fgets() to retrieve an entire line of input first, and use sscanf() to do parsing. This allows for better error recovery, since an error can be diagnosed by the line that caused the error, and the line can be gracefully skipped as well. scanf() is meant for structured input, and can only give you a rough idea of where a scanning error occurred. And, errors cause the input to jam, leading to confusing debugging sessions at times.

Upvotes: 6

Related Questions