Zen Mournster Zen Mournster - 1 month ago 5
C Question

Scanf/Printf in C...what's going on here?

I am self-learning C and I am currently studying the Scanf and Printf functions.

I adapted this program to test myself:

char topping[24];
int slices;
int day, year;
float cost;
char month[10];

printf(" How much does a pizza cost in your area?\n");
scanf(" %f", &cost);

printf("What is your favorite one-word pizza topping?\n");
scanf(" %s",topping);
printf("How many slices of %s pizza, topping can you eat in one sitting\n",topping);
scanf(" %d", &slices);

printf(" What is today's date (enter in the following format 1-Jan-2016 )\n");
scanf(" %d-%s-%d", &day, month, &year);
printf("\nWhy not treat yourself to dinner on %d-%s-%d and have %d slices of %s pizza ? It will only cost you %.2f", day, month, year,slices, topping,cost);

The purpose of the exercise is for me to grasp an understanding of scanf functions and how "delicate" they can be.

My test program here runs well...except for the output in the year variable.

Why is the output in the year variable spitting out gibberish and how can I fix it?

Thank you.


Here's the problem. The %s specifier means to read any characters up until the next whitespace. So , after %d- has matched 1-, then the %s matches Jan-2016. Then the next %d fails as there is nothing left to match.

First of all you should always be checking the return value of scanf so you know whether there was a matching failure. For example in this case:

if ( 3 != scanf(" %d-%s-%d", &day, month, &year) )
    printf("Matching failure occurred.\n");
    // do something else...
     printf("Why not treat yourself...

Secondly, to actually avoid the problem. The scanf function is pretty limited as you can see. To use other delimiters instead of whitespace, you can use the scanset specifier %[.....] instead:

scanf(" %d-%9[^-]-%d", &day, month, &year)

(with the same error checking). The scanset specifier means to read any characters (possibly including whitespace) that matches the characters inside the [], except that a ^ indicates to NOT match the next character. So this will read everything up until the next -. Also I added the 9 to avoid overflowing your buffer of size 9+1.

Of course this means if the person never types another - then the program goes a bit weird. You can fix this by making the format string more and more complicated; or you can instead read an entire line with fgets and then use the sscanf function with the aforementioned string. This will catch the case of the person pressing Enter before typing another -.

In fact it turns out it's usually a good idea to read a whole line at a time and then go back and process that line.

At some stage you will get tired of how awful scanf is, and make your own parser.