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

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.

Related

Trying to understand how different ways of input happen in C however the fgets() tends to skip

I am new to C and trying to learn how different inputs work. I wrote the this code to try getChar(), sscanf(), and fgets(). My first fgets() works perfectly fine but it skips the second one after I ask the user to enter a date. Am I using these functions in a way they are not supposed to be used. What are possible ways to solve this.
Also are there any other ways of receiving user input that would be more beneficial given certain scenerios.
#include <stdio.h>
#define MAX 12
#define MAX_DATE 100
int main(int argc, const char * argv[]) {
char buf[MAX];
char date[MAX_DATE];
char day[9], month[12];
int year;
printf("This code shows various ways to read user input and also how to check for input\n");
printf("Enter a String less than 11 characters for input: ");
fgets(buf, MAX, stdin); //stdin is used to indicate input is from keyboard
printf("Enter a char: ");
char inputChar = getchar(); //gets next avalible char
printf("\nThe char you entered is: "); putchar(inputChar); //puts char prints a char
printf("\nsscanf allows one to read a string and manupilate as needed.\n");
printf("\nEnter a date as follows: Day, Month, Year");
fgets(date, MAX_DATE, stdin);
sscanf(date, "%s, %s, %d", day, month, &year);
printf("\nFormatted values as follows... \n");
printf("day: %s\n", day);
printf("month: %s\n", month);
printf("year: %d\n", year);
return 0;
}
/*
Output for the code:
This code shows various ways to read user input and also how to check for input
Enter a String less than 11 characters for input: hey
Enter a char: a
The char you entered is: a
sscanf allows one to read a string and manupilate as needed.
Enter a date as follows: Day, Month, Year
Formatted values as follows...
day:
month:
year: -1205589279
Program ended with exit code: 0
*/
Your second fgets is not being skipped. It is getting the rest of your line.
In your example, when prompted by "Enter a char: ", you are entering "a" followed by a newline. getchar gets the "a" character. fgets starts at the character directly after that, meaning it is reading the newline after the "a" and returning.
If you call fgets(buf, MAX, stdin); after your getchar() to discard the rest of the line, your program will work as you expect.
#contrapants nicely explains the reason for the "skips the second one". When the user types a Enter, the 'a' is read by getchar() and the '\n' is then read by fgets(), without waiting for additional input.
For a learner, I recommend to only use fgets() for input.
printf("Enter a char: ");
fgets(buf, sizeof buf, stdin);
char inputChar = 0;
sscanf(buf, "%c", &inputChar);
Am I using these functions in a way they are not supposed to be used.
A side issue occurs when reading into a buffer without insuring no overflow. Use width limits.
char day[9], month[12];
//sscanf(date, "%s, %s, %d", day, month, &year);
int count = sscanf(date, "%8s , %11s , %d", day, month, &year);
if (count != 3) {
Handle_unexpected_input_somehow();
}

C scanf not working as intended (Help!)

Was working on a program that prompts a user to enter a phone number and than prints it out using . instead of - so and when I run it it doesn't even let me input anything it just runs and gives me random values. So here's a look at the full program.
int item_number, year, month, day, first, middle, last;
//float unit_price;
printf("Enter item number: ");
scanf("%d", &item_number);
printf("Enter unit price: ");
scanf("%f", &unit_price);
printf("Enter purchase date (mm/dd/yyyy): ");
scanf("%d /%d /%d", &month, &day, &year);
printf("Item\t\tUnit\t\tPurchase\n\t\tPrice\t\tDate");
printf("\n%d\t\t$%6.2f\t\t%.2d/%.2d/%.2d\n", item_number, unit_price, month, day, year);
//here is the code that gives me the problem explained above.
//also if i comment the code above it works.
printf("Enter phone number [(xxx) xxx-xxxx] : ");
scanf("(%d) %d - %d", &first, &middle, &last);
printf("You entered %d.%d.%d", first, middle, last);
The problem you have encountered, is probably one of the most common problems encountered by new C programmers -- the improper use of scanf. Specifically, when you attempt to read the telephone number, stdin contains, e.g.:
"\n(888) 555-1212"
(the '\n' the result of pressing Enter after (mm/dd/yyyy) is entered)
As a result, the input waiting in stdin does not match "(%d...", and a matching failure results. Why? There is a newline at the beginning of the characters in stdin. The "%d" format specifier (all numeric conversion specifiers) will skip leading whitespace.
However, the leading whitespace does not precede the integer, it precedes the "(" which is not skipped by your format string. With scanf, a " " (space) in the format string, will cause any number of whitespace characters to be skipped/discarded. So as BLUEPIXY correctly notes, you need to add the space before the "(" in the format string to have scanf ignore the '\n' waiting in stdin.
Beyond that, you make the same mistake and misuse of scanf that nearly all new C-programmers do -- failing to check the return. scanf returns the number of successful conversions that take place based on the conversion specifiers in the format string.
At minimum, you must check the return of scanf (and in fact on ALL USER INPUT functions) to provide minimal validation that you do in fact have valid input stored in your variables to proceed forward with in your code. If you fail to check the return, you can have no confidence that undefined behavior isn't being invoked from that point forward. So validate all user input.
A minimal rewrite of your code that puts those pieces together would be:
#include "stdio.h"
int main (void) {
int item_number, year, month, day, first, middle, last;
float unit_price;
printf("Enter item number: ");
if (scanf ("%d", &item_number) != 1) { /* validate item */
fprintf (stderr, "error: invalid input (item_number)\n");
return 1;
}
printf("Enter unit price: ");
if (scanf ("%f", &unit_price) != 1) { /* validate unit */
fprintf (stderr, "error: invalid input (unit_price)\n");
return 1;
}
printf("Enter purchase date (mm/dd/yyyy): ");
/* validate date */
if (scanf ("%d /%d /%d", &month, &day, &year) != 3) {
fprintf (stderr, "error: invalid input (mm/dd/yyyy)\n");
return 1;
}
printf ("\t\tUnit\t\tPurchase\nItem\t\tPrice\t\tDate");
printf ("\n%d\t\t$%6.2f\t\t%.2d/%.2d/%.2d\n",
item_number, unit_price, month, day, year);
printf ("Enter phone number [(xxx) xxx-xxxx] : ");
/* validate phone */
if (scanf (" (%d) %d - %d", &first, &middle, &last) != 3) {
fprintf (stderr, "error: invalid input [(xxx) xxx-xxxx]\n");
return 1;
}
printf ("You entered %d.%d.%d\n", first, middle, last);
return 0;
}
Example Use/Output
$ ./bin/scanf_phone
Enter item number: 3
Enter unit price: 19.95
Enter purchase date (mm/dd/yyyy): 03/01/2017
Unit Purchase
Item Price Date
3 $ 19.95 03/01/2017
Enter phone number [(xxx) xxx-xxxx] : (800) 555-1212
You entered 800.555.1212
(note I tweaked the format to put Item on the 2nd line...)
Look things over, and spend the time it takes to understand man 3 scanf. It is time well spent.
If you are using Xcode, then write your printf statements like so:
printf("Enter item number:\n");
Put a newline(\n) at the end.

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;
}

Writing a C program that calculates average quarterly rainfall for a city?

I'm struggling with a program I need to write for class. I need to write a program that reads a city's name from the user and then asks the user to enter the month followed by a comma and then the average rainfall for that month. Here's the task at hand:
Write a program that reads data from the user about the quarterly
rainfall in a certain city and displays it on the screen. Your program
must prompt the user the following information:
The name of the city. You may assume it is at most 50 characters.
The months and amount of rainfall received for each month. You may assume, for each month, the user will enter both the month and
rainfall received values in one line separated by a comma with the
month having a length of three characters.
The format of the output in terms of field width and precision.
Your program must then calculate the average rainfall and produce
output complying with the following specifications:
Display the name of the city followed by a blank line.
For each monthly rainfall value, display the name of the month left justified in the user specified field width followed by the rainfall
for that month displayed right justified formatted using fixed-point
notation, with the user specified precision, in a field of 15 spaces
wide.
Finally follow last month's rainfall with a blank line and then on a separate line display the sentence "Average rainfall: " left justified
in the user specified field width followed by the average rainfall
right justified in fixed-point notation with the user specified
precision and in a field of 15 spaces wide.
Now here's my code so far, I'm struggling to get the code right to let the user enter his own comma, the code compiles and runs, but it won't print the next month's line, after hitting enter after entering the first month's details, it just leaves a blank line:
int main ()
{
char cityName[50];
char monthName[3];
char comma;
float aveRain = 0;
int monthCount = 1;
float aveResult = 0;
int fieldWidth;
int outputPrecision;
puts("This program calculates the average quarterly rainfall for a given city.");
printf("Enter the name of the city: ");
scanf("%s" , &cityName[50]);
while( monthCount <= 3 )
{
printf( "Enter the month and average rainfall of month %d: " , monthCount);
scanf( "%s %s %f" , &monthName[3] , &comma , &aveRain);
monthCount = monthCount + 1;
}
}
Your scanf is bad :
you declare char monthName[3] (only 2 chars and the terminating null) and read at &monthName[3] just after the end of the array : undefined behaviour
you try to read with %s in a char : as %s reads at least one character and writes a terminating null, here again you are writing anywhere with UB
You should instead :
declare char monthName[4] to leave room for terminating null
write cr = scanf("%3s,%f", monthName, &aveRain); in order to :
limit input to at most 3 characters and a null in monthName
process the comma
be able to control that you correctly scanned 2 fields or abort with an error message is case of problem on input
BTW the preceding scanf was also bad : you must read in the char array and not after it :
scanf("%49s" , cityName);

reading a date with sscanf

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))
{
}

Resources