reading a date with sscanf - c

I've got to read a date format (dd-mm-yyyy;) from a char* string using sscanf with this line of code:
sscanf(string, "%[^-]-%[^-]-%[^;];", day, month, year)
where day/month/year are char* string of 3/3/5 elemets each.
In this way it works but when i try to use day/moth/year as integer variables (with same sscanf), I got a 0 0 0 value when i use printf on them. If i change sscanf to
sscanf(string, "%d-%d-%d;", day, month, year)
I got segmentation fault.
Anyone can help me? Using K&R book, I didn't find a solution.

You need to pass the address of the int variables:
int day, month, year;
sscanf(string, "%d-%d-%d;", &day, &month, &year);
sscanf() returns the number of assignments made, recommend checking the return value before using day, month and year:
if (3 == sscanf(string, "%d-%d-%d;", &day, &month, &year))
{
}

Related

How to print a given date in C

I am very new to C programming. I was trying to use the scanf function to ask the user to enter a date and display it in the console. So wrote the following codes:
#include <stdio.h>
#include <stdlib.h>
int main() {
int date, month, year;
printf("Please enter the date in the form of dd/mm/yyyy: ");
scanf("%d/%d/%d", &date, &month, &year);
printf("the date you entered was: %d-%d-%d\n", date, month, year);
return 0;
}
But the output am getting is not in a proper format, for example, I type in "10-12-2016", but the result I get was "10-554502544-32766". Any idea guys? Thanks in advance.
In your scanf(), you have this format - %d/%d/%d but you are giving the input as 10-12-2016, so you are doing wrong!
Instead, you should give input as - 10/12/2016 and the %d/%d/%d part in scanf() will ignore the / part from the input.
I type in 10-12-2016, but the result I get was 10-554502544-32766. Any idea guys?
Yes, when you are giving 10-12-2016 as input, scanf() assigning only 10 to date variable but no value to the other variables. Since the other two variables month and year is uninitialized, you are getting garbage value (554502544 and 32766) when you print the value of variable month and year.
One way to check this: Just initialize the variable and then take input.
int date = 0, month = 0, year = 0;
scanf("%d/%d/%d", &date, &month, &year);
Now, if you give 10-12-2016 as input, you will get 10-0-0 as output. Hopefully you can understand what is actually happening!
scanf() is a fairly kludgy tool. It expects the format to be exactly as you specified and if it isn't you get weird behaviour.
You either need to enter the text exactly as specified (dd/mm/yy, not dd-mm-yy) or change how you go about things.
Consider having scanf() scan in a string that you then lex yourself to get the values you want - you can be much more tolerant of variances in the input that way, as well as be more proof against someone trying to break your program by deliberately giving it invalid input.
You need to check the return value from scanf - See the manual page
#include <stdio.h>
#include <stdlib.h>
int main() {
int date, month, year;
printf("Please enter the date in the form of dd/mm/yyyy: ");
if (scanf("%d/%d/%d", &date, &month, &year) == 3) {
printf("the date you entered was: %d-%d-%d\n", date, month, year);
} else {
printf("You have made an error\n");
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int date, month, year;
printf("Please enter the date in the form of dd press enter then enter mm then press enter then enter year then press enter.. ");
scanf("%d", &date);
scanf("%d", &month);
scanf("%d", &year);
printf("the date you entered was: %d/%d/%d\n", date, month, year);
return 0;
}

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");
printf("$");
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...
}
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.

How to scan a "0" on the months that have one digit?

I am doing this C program where I need to input a date and see whether it is a valid date. However, I do not know how to scan a "0" in front of the days and months that have one digits. Also, the program requires to scan "/" as well. If the user inputs "07-14-1999" it has to be invalid because the user did not input "/". What should I do with these two problems? The following is the code I have so far. Thank you.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int day, month, year;
printf("Please enter a date to check validity (in the form of MM/DD/YYYY): ");
scanf("%i%i/%i%i/%i%i",&month, & month, &day, &day, &year, &year, &year &year);
printf("%i%i/%i%i/%i%i",month, month, day, day, year, year, year, year);
}
You want to scan three integer numbers, so you should use %d once for each number in scanf:
scanf("%d/%d/%d", &month, &day, &year);
To validate input it makes sense to check number of successfully scanned integers:
int res = scanf("%2d/%2d/%4d", &month, &day, &year);
if (res != 3) {
/* error */
}
Here %2d means that the max length of that input integer is 2 digits.
If everything is scanned correctly you can validate ranges for month, day and year.
To print leading zero:
printf("%02d/%02d/%04d", month, day, year);
Here %02d means that the integer is printed by minimum two symbols and zero is prepended if there is only one symbol.
It is trickier to make sure that the number of input symbols is correct. The above scan pattern also accepts date "1/1/1999". To simplify and to avoid scanning each symbol separately it is possible to read input as a string:
int day, month, year;
/* buffer length is enough for 10 date symbols + 1 null terminating
* character + 1 for too long input */
char buf[12];
char dummy_end_test;
printf("Please enter a date to check validity (in the form of MM/DD/YYYY): ");
/* scan as a string with maximum field width 11, check that the number
* of input characters is exactly 10 */
if (scanf("%11s", buf) != 1 || strlen(buf) != 10) {
printf("incorrect input length\n");
return 1;
}
/* parse integer numbers from string
* try to read symbol dummy_end_test to filter input as 11/1/19999 or 11/11/199x
* if it is possible to read one more character after four digits of year
* the number of scanned entries is 4 that is invalid input */
int ret = sscanf(buf, "%2d/%2d/%4d%c", &month, &day, &year, &dummy_end_test);
if (ret != 3) {
printf("error\n");
return 1;
}
Here I used sscanf that scans formatted input from string.
Anyway it is needed to validate ranges for day, month and year. All those numbers must be greater than 0. Maximum day depends on month and/or on leap year.

what will be answers to the below questions , which options will not read the date in given format?

Which of the following three C code snippets WILL NOT read a date as three integers as follows:as int day, month, year;
a. printf("Enter date: "); scanf("%d/%2d/%2d", day, month, year);
b. printf("Enter date: "); gets( day); gets( month); gets( year);
c. printf("Enter date: ");scanf("%d", day); scanf("%d", month); scanf("%d", year);
If day, month and year are not pointers to int, then non of them will work. Otherwise
Option b will not read date as integer. gets was used earlier to read strings (it has been now omitted from the C standard).

fscanf how to import a date like 20.20.2012 to one variable?

while (fscanf(ifp, " %d %d kl. %d %s - %s %d - %d %d\n", &round, &date, &clock, teeam, &goals, &attendance)
I should probably know this, but the second %d should import a date to my variable, like 20.20.2012 but instead i only get the first 20 and not rest of it.
thank you :)
Internally, the string is read as long as it represents a valid integer (so it stops when '.' is encountered).
How would you represent the date as one integer? You could have 3 variables and read them like this:
fscanf(ifp, "%d.%d.%d", &day, &month, &year);
By the way, 20/20 is a strange date :-)
The %d format specifier lets you scan a single numeric value, not a sequence of three numbers.
You can read a date in the format that you expect like this:
char date_buf[11];
scanf("%10[0-9.]", date_buf);
The text is not parsed as three ints, but stored as a text instead. You can break it into a month, a day, and a year like this:
int month = atoi(&date_buf[0]);
int day = atoi(&date_buf[3]);
int year = atoi(&date_buf[6]);

Resources