I am a newbie to coding and I am trying to code for the "Friday the Thirteenth" problem posted in USACO, which requires us to compute the frequency that the 13th of each month lands on Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, and Saturday over a given period of N years. The time period to test will be from January 1, 1900 to December 31, 1900+N-1 for a given number of years, N. N is positive and will not exceed 400.
It was given that Jan 1, 1900 was on a Monday. We are not supposed to use any in-built functions.
I tried to solve this problem with a different approach (which I think isn't the best approach). My code (in C) is given below:
#include<stdio.h>
int daysInMonth (int month, int year)
{
/*
30 should be returned if the months are Apr, June, Sept and Nov.
31 should be returned in all other cases.
29 should be returned if the month is Feb and the year is a leap year
*/
if (month == 1) //Feb
{
if (year % 4 == 0 || (year % 100 != 0 && year % 400 == 0)) //leap year
return 29;
else
return 28;
}
switch (month)
{
case 3:
case 5:
case 8:
case 10: return 30;
default: return 31;
}
}
void main ()
{
int month, year, n, i, noOfDays, start = 0, result[] = { 0, 0, 0, 0, 0, 0, 0 }, day = 0, daycheck = 1;
scanf ("%d", &n);
for (year = 1900; year <= 1900 + n - 1; ++year)
{
for (month = 0; month < 12; ++month)
{
if (month == 0 && year == 1900) // to identify the first 13th and the day it falls on
{
while (daycheck != 13)
{
++daycheck;
day = (day + 1) % 7;
}
++result[day];
}
else
{
if (month == 0) //If January, add the noOfDays of the prev. month i.e. December
noOfDays = 31;
else
noOfDays = daysInMonth (month - 1, year);
day += (noOfDays - 28); // Adding a multiple of 7 (here, 28) does not change the day
day %= 7;
++result[day];
}
}
}
for (i = 0; i < 7; ++i)
printf("%d ", result[(i + 5) % 7]); //Sat, Sun, Mon, Tue, Wed, Thu, Fri
}
For an input of 20, the expected output is 36 33 34 33 35 35 34.
However, my output turns out to be 35 35 33 35 32 35 35.
Even though my answer is within the range of the expected output, there's something wrong with my logic that makes it erroneous.
I would appreciate if someone could point out the error. I would also be happy if you could suggest a better way to approach this problem. I am a student of Computer Science and am yet to learn about algorithms in detail.
Your leap year condition is wrong.
Change the Leap year condition as follows.
int daysInMonth (int month, int year)
{
if (month == 1) //Feb
{
if (( year%400 == 0)|| (( year%4 == 0 ) &&( year%100 != 0)))
return 29;
else
return 28;
}
Related
In my program, I am asking the user to input a date (in just integers such as 12 31 2019 367) and the number of days they add to it. In one of my functions, this is precisely what I am doing.
The user inputs 12 31 2019 367, and the program is meant to print 1 1 2021, but instead prints 1 1 2020 (a year behind)...
What I did (sorry for a lot of code, I tried to keep it simple and clean):
int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
void add_days_to_date(int *mm, int *dd, int *yy, int days_left_to_add)
{
int days_left_in_month;
while(days_left_in_month > 0)
{
days_left_in_month = days_in_month[*mm] - *dd;
// days_left_in_month = days_in_month[*mm] - *dd;
if (days_in_month[2] && is_leap_year(*yy) == true)
{
days_left_in_month++;
}
} // end while
printf("after while\n");
if(days_left_to_add > days_left_in_month)
{
days_left_to_add -= days_left_in_month;
*dd = 1;
if(*mm == 12)
{
*mm = 1;
(*yy)++;
}
else
{
(*mm)++;
}
}
else
{
*dd += days_left_to_add;
days_left_to_add = 0;
}
}
int main()
{
int mm, dd, yy, days_left_to_add;
printf("Please enter a date between the years 1800 and 10000 in the format mm dd yy and provide the number of days to add to this date:\n");
scanf("%d %d %d %d", &mm, &dd, &yy, &days_left_to_add);
// printf("\nREAD\n");
//These are pointers, so they have to be at certain location i.e. int* mm = &mm
add_days_to_date(&mm, &dd, &yy, days_left_to_add);
printf("%d %d %d\n", mm, dd, yy);
}
What I got after inputs:
Inputs: 12 31 2019 367
Output: 1 1 2020 (meant to be 1 1 2021)
Your loop in the function needs to be while (days_left_to_add > 0), and should cover the whole of the function (and then needs some minor adjustments). As it is, you add just one month, which given that your input is 2019-12-31 lands you on 2020-01-01.
Your code should validate the input date.
This code works, at least for a number of test cases similar to your example.
/* SO 74925-5084 */
#include <stdio.h>
#include <stdbool.h>
static const int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static bool is_leap_year(int year)
{
if (year % 4 != 0)
return false;
if (year % 100 != 0)
return true;
if (year % 400 != 0)
return false;
return true;
}
static void add_days_to_date(int *mm, int *dd, int *yy, int days)
{
while (days > 0)
{
int days_left_in_month = days_in_month[*mm] - *dd + 1;
if (*mm == 2 && is_leap_year(*yy))
days_left_in_month++;
//printf("DAYS = %2d, DLIM = %2d, leap(%4d) = %s\n",
// days, days_left_in_month, *yy, is_leap_year(*yy) ? "true" : "false");
if (days >= days_left_in_month)
{
days -= days_left_in_month;
*dd = 1;
if (*mm == 12)
{
*mm = 1;
(*yy)++;
}
else
{
(*mm)++;
}
}
else
{
*dd += days;
days = 0;
}
// This is informative while debugging
printf("%.4d-%.2d-%.2d + %d\n", *yy, *mm, *dd, days);
}
}
int main(void)
{
int mm, dd, yy, days_left_to_add;
printf("Please enter a date between the years 1800 and 10000 in the format mm dd yyyy\n"
"and provide the positive number of days to add to this date:\n");
if (scanf("%d %d %d %d", &mm, &dd, &yy, &days_left_to_add) != 4)
{
fprintf(stderr, "Failed to read 4 numbers\n");
return 1;
}
printf("Input: %.4d-%.2d-%.2d + %d\n", yy, mm, dd, days_left_to_add);
/* Data validation */
if (days_left_to_add <= 0)
{
fprintf(stderr, "The number of days to add must be a positive number (unlike %d)\n",
days_left_to_add);
return 1;
}
if (yy < 1800 || yy > 10000)
{
fprintf(stderr, "Year %d is outside the range 1800..10000\n", yy);
return 1;
}
if (mm < 1 || mm > 12)
{
fprintf(stderr, "Month %d is outside the range 1..12\n", mm);
return 1;
}
int dim = days_in_month[mm];
if (mm == 2 && is_leap_year(yy))
dim++;
if (dd < 1 || dd > dim)
{
fprintf(stderr, "Day %d is outside the range 1..%d\n", dd, dim);
return 1;
}
add_days_to_date(&mm, &dd, &yy, days_left_to_add);
printf("%d %d %d\n", mm, dd, yy);
return 0;
}
Sample runs (program ad41 created from ad41.c):
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2019 367
Input: 2019-12-31 + 367
2020-01-01 + 366
2020-02-01 + 335
2020-03-01 + 306
2020-04-01 + 275
2020-05-01 + 245
2020-06-01 + 214
2020-07-01 + 184
2020-08-01 + 153
2020-09-01 + 122
2020-10-01 + 92
2020-11-01 + 61
2020-12-01 + 31
2021-01-01 + 0
1 1 2021
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2018 60
Input: 2018-12-31 + 60
2019-01-01 + 59
2019-02-01 + 28
2019-03-01 + 0
3 1 2019
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2019 60
Input: 2019-12-31 + 60
2020-01-01 + 59
2020-02-01 + 28
2020-02-29 + 0
2 29 2020
$
I need to write a program in C that it prints a month chosen by the user from the year 2022.
If the user enter January (has 31 days) and the user enter to print 20 days, then should be printed from 1st January untill 20 January.
Same for every month.
I have this pice of code but I'm not happy with it and I googled everything.
void print_month(char *mo, int number_day_userInput){
int i,j; // as counters
int week = 7; // as 7 days in a week
int day=1;
int day_of_the_week=1;
printf("M\tT\tW\tT\tF\tS\tS");
//January
if(strcmp(mo, "January")== 0){
for(i=0;i<=5;i++){ // this 5 is as 5 weeks in January
printf("\n");
for(j=1;j<=week;j++){
if(day_of_the_week>=6){ // 1st day start printing
printf("%i",day);
day++;
if(day > number_day_userInput){
break;
}
}
day_of_the_week++;
printf("\t");
}
}
printf("\n\nJanuary has 31 days");
}
I can't figure it out, how to determine for each month where to start printing the first day. For example, January 1st starts on a Saturday, the 6th day. February starts on 2nd day. Also, I don't know how to determine how many weeks are in a month. Could you please share some ideas ? Not necessarily in C, but an advice will be welcomed. Thank you
Here I started with Sunday as day 0 (Gregorian calendar). It should print out correctly based on the month given. Core concept here is just using the modulus operator % to find remainders, and basic for-loop stuff :)
#include <stdio.h>
#include <string.h>
static int daysOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static int start = 6;
void print_month(char *mo, int number_day_userInput)
{
int j = 0;
if(strcmp(mo, "February") == 0) { j = 1; }
else if(strcmp(mo, "March") == 0) { j = 2; }
else if(strcmp(mo, "April") == 0) { j = 3; } // and so on...
for(int i = 0; i < j; ++i)
{
start += daysOfMonth[i];
}
int startDay = start % 7;
printf("S\tM\tT\tW\tT\tF\tS\n");
for(int tab = 0; tab < startDay; ++tab)
{
printf("\t");
}
for(int day = 1; day <= number_day_userInput; ++day)
{
printf("%d\t", day);
if(++startDay % 7 == 0)
{
printf("\n");
}
}
printf("\n");
}
int main()
{
print_month("March", 20);
}
SAMPLE OUTPUT of print_month("January", 31):
S M T W T F S
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
I am trying to print out a calendar for a specific year and month but keep getting the same calendar for every month. I tried to also add a statement to see if the year is a leap year to add to the number of days but it made no difference. I am new to c.Please help with any suggestions. Thanks in advance.
void print_month_calendar(int year, int month)
{
int day;
int daycode = ddaycode(year);
int days_in_month[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
char *months[]=
{
" ",
"\n\n\nJanuary",
"\n\n\nFebruary",
"\n\n\nMarch",
"\n\n\nApril",
"\n\n\nMay",
"\n\n\nJune",
"\n\n\nJuly",
"\n\n\nAugust",
"\n\n\nSeptember",
"\n\n\nOctober",
"\n\n\nNovember",
"\n\n\nDecember"
};
printf("%s", months[month]);
printf("\n\nSun Mon Tue Wed Thu Fri Sat\n");
if(( year%4==0 && year%100 !=0) || year%400==0)
days_in_month[2] = 29;
for (day = 1; day <= 1 + daycode * 5; day++)
{
printf(" ");
}
//Print all the dates for the month
for (day = 1; day <= days_in_month[month]; day++)
{
printf("%2d", day);
if ((day + daycode) % 7 > 0)
printf(" ");
else
printf("\n ");
}
}
int ddaycode(int year)
{
int daycode;
int d1, d2, d3;
d1 = (year - 1.)/ 4.0;
d2 = (year - 1.)/ 100.;
d3 = (year - 1.)/ 400.;
daycode = (year + d1 - d2 + d3) %7;
return daycode;
}
You have to know the first weekday in the month. You can use localtime to go to specific date, use mktime to get struct tm data which contains weekday. In addition, you can use strftime to get the month name. Example:
void print_month_calendar(int year, int month)
{
time_t rawtime;
struct tm * timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
timeinfo->tm_year = year - 1900;
timeinfo->tm_mon = month - 1;
timeinfo->tm_mday = 1;
mktime(timeinfo);
//sunday is 1 ... saturday is 7
int weekday = 1 + timeinfo->tm_wday;
int days_in_month[] = { 0, 31,28,31,30,31,30,31,31,30,31,30,31 };
if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))
days_in_month[2]++;
char monthname[30];
strftime(monthname, sizeof(monthname), "%B", timeinfo);
printf(" %s %d\n", monthname, year);
printf(" Su Mo Tu We Th Fr Sa\n");
int day = 1;
for (int i = 1; i <= 40; i++)
{
if (i < weekday)
{
printf(" ");
}
else
{
printf("%3d ", day);
if (day == days_in_month[month])
break;
day++;
if ((i % 7) == 0)
printf("\n");
}
}
printf("\n");
}
int main()
{
print_month_calendar(2016, 10);
return 0;
}
ideone example
October 2016
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
I'm trying to output a calendar in C and I think I've got the format down, but I'm having trouble with:
Validating user input (I've commented out the potential solution, but it hasn't compiled correctly yet. It always prints the "invalid year/month selected" and the break statement doesn't work.)
Starting the calendar days on the correct day of the week (May of 2018 starts on Tuesday, not on Sunday)
My current output:
Enter month: 5
Enter year: 2018
Su M Tu W Th F Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
My desired output:
Enter month: 5
Enter year: 2018
Su M Tu W Th F Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Here's my program:
#include <stdio.h>
#include <stdlib.h>
/* #defines */
#define BEGIN 1900
#define DAYS_IN_WEEK 7
/* function prototypes */
void getMonthYear(int *month, int *year);
int toJulian(int month, int day, int year);
int daysInMonth(int month, int year);
int leapYear(int year);
long yearsToDays(int year);
void printCalendar(int startDay, int numDays);
void printHeader();
/* Calendar.c: Prints monthly calendar. Lab 4 / Week 9 */
void main(void)
{
int month, year;
int startDay; // what day is first day of month. 1/1/1900 was Monday, so...
// day 1 is Mon, day 2 is Tue, ... , day 0 is Sun
getMonthYear(&month, &year);
startDay = (toJulian(month, 1, year) + yearsToDays(year)) % DAYS_IN_WEEK;
printCalendar(startDay, daysInMonth(month, year));
}
void getMonthYear(int *month, int *year) {
printf("Enter month: ");
scanf("%d", month);
/*if (month < 1 || month > 12) {
printf("Invalid month selected");
//break;
}*/
printf("Enter year: ");
scanf("%d", year);
/* if (year < BEGIN) {
printf("Invalid year selected");
//break;
}*/
printf("\n");
}
int toJulian(int month, int day, int year) {
int count;
for(count = 1; count < month; ++count) {
day += daysInMonth(month, year);
}
return day;
}
int daysInMonth(int month, int year) {
int numDays;
switch (month) {
case 1: numDays = 31;
break;
case 2: numDays = 28;
break;
case 3: numDays = 31;
break;
case 4: numDays = 30;
break;
case 5: numDays = 31;
break;
case 6: numDays = 30;
break;
case 7: numDays = 31;
break;
case 8: numDays = 31;
break;
case 9: numDays = 30;
break;
case 10: numDays = 31;
break;
case 11: numDays = 30;
break;
case 12: numDays = 31;
break;
}
return numDays;
}
int leapYear(int year) {
if (year % 400 == 0 && (year % 100 != 0 || year % 400 == 0)) {
return 1;
}
else {
return 0;
}
}
long yearsToDays(int year) {
int count;
long days;
for (count = BEGIN; count < year; ++count) {
days = 365 + leapYear(year);
}
return days;
}
void printCalendar(int startDay, int numDays) {
int dayid;
printHeader();
// Shifts position for the first date... sort of
for ( dayid = 0; dayid < startDay; dayid++ ) {
printf(" ");
}
// Supposedly prints all the dates for one month
for ( dayid = 1; dayid <= numDays; dayid++ ) {
printf("%3d", dayid );
// If the day is not before Saturday, start next line on Sun
if ( ( dayid + startDay ) % DAYS_IN_WEEK > 0 ) {
printf(" ");
}
else {
printf("\n" );
}
}
}
void printHeader() {
printf(" Su M Tu W Th F Sa\n");
}
break is used for exiting loops or switch statements. It can only be used inside a loop inside the current function scope.
So even if getMonthYear() were called inside a loop in main() (which it isn't), a break inside it will not exit that loop.
As it is, you have no loop at all, neither in getMonthYear(), nor in the calling sequence leading to it, so the break would be a no-op.
You have to ask yourself "what do I actually want to do when they make an invalid entry?"
One possibility would be to return the validity from getMonthYear()
bool valid_input = 0;
while (!valid_input) {
valid_input = getMonthYear(&month, &year);
}
To deal with the problem of getting the day correct, you probably need to do a little more debugging yourself: put print statements in all the places where there are calculations, print out the intermediate results, and find out where you have an error that way.
You have errors in the following functions:
toJulian
int toJulian(int month, int day, int year) {
int count;
for(count = 1; count < month; ++count) {
day += daysInMonth(month, year);
}
return day;
}
You are using the month in every call. You need to use count.
You don't need the input argument day. You can have a local variable that is initialized to 0 before the loop starts.
The updated version:
int toJulian(int month, int year) {
int count;
int days = 0;
for(count = 1; count < month; ++count) {
days += daysInMonth(count, year);
}
return days;
}
leapYear.
int leapYear(int year) {
if (year % 400 == 0 && (year % 100 != 0 || year % 400 == 0)) {
return 1;
}
else {
return 0;
}
}
The logic in the if statement is not correct. It needs to be:
(year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
You can make the function to be more readable and less error prone by using:
int leapYear(int year) {
int ret = 0;
if ( year % 4 != 0 )
{
ret = 0;
}
else
{
if ( year % 100 != 0 )
{
ret = 1;
}
else
{
ret = (year % 400 == 0);
}
}
return ret;
}
yearsToDays
long yearsToDays(int year) {
int count;
long days;
for (count = BEGIN; count < year; ++count) {
days = 365 + leapYear(year);
}
return days;
}
You have not initialized days.
You are not accumulating the number of days. You are just assigning a value. The last returned value gets returned instead of the accumulated number of days.
You are using year in the loop instead of count in the argument to leapYear.
Here's the updated version:
long yearsToDays(int year) {
int count;
long days = 0;
for (count = BEGIN; count < year; ++count) {
days += 365;
days += leapYear(count);
}
return days;
}
printCalendar
void printCalendar(int startDay, int numDays) {
int dayid;
printHeader();
// Shifts position for the first date... sort of
for ( dayid = 0; dayid < startDay; dayid++ ) {
printf(" ");
}
// Supposedly prints all the dates for one month
for ( dayid = 1; dayid <= numDays; dayid++ ) {
printf("%3d", dayid );
// If the day is not before Saturday, start next line on Sun
if ( ( dayid + startDay ) % DAYS_IN_WEEK > 0 ) {
printf(" ");
}
else {
printf("\n" );
}
}
}
You are using up four spaces when printing the days of the month - "%3d" and " ". You need to write four spaces for each day up to startDay in the first for loop. Otherwise, the first row of output won't be properly aligned.
You need to use:
for ( dayid = 0; dayid < startDay; dayid++ ) {
printf(" ");
}
main
The line
startDay = (toJulian(month, 1, year) + yearsToDays(year)) % DAYS_IN_WEEK;
should be
startDay = (1 + toJulian(month, year) + yearsToDays(year)) % DAYS_IN_WEEK;
to account for (1) the fact that 1900-Jan-01 falls on a Monday and (2) change to the interface of toJulian.
I'm stuck on a program that takes the user's desired year and prints out a 12 month calendar for the same year. This is all I have so far and I'm pretty sure I have the right way to figure out whether the year is a leap year (in the code) and how to find out when the 1st of Jan is (underneath first with just variables then filled in). Also I am trying to print this in normal Calendar format with the month on top then the days of the week underneath followed by the day numbers. Any help would be appreciated.
Find first day:
h = (1 + [(13(m + 1))/5] + K + [K/4] + [J/4] - 2J) mod 7
h = (1 + [(13(13 + 1))/5] + (year % 100) + [(year % 100)/4] + [(year/100)/4] - 2(year/100) % 7
H is the starting day, M is the month, K is yr % 100, J is yr / 100.
/* Calendar.c */
#include <stdio.h>
int main(void){
int year, month, date;
int startingDay; /* initfrom user input*/
printf("Enter the year of your desired calendar: ");
scanf("%d\n", &year);
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
int months[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
else
int months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
for (month = 0; month < 12; month++) {
const int daysInMonth = ; /* set # of days */
int dayOfWeek;
printf(…); //month name
printf(…); //days of week
for (dayOfWeek = 0; dayOfWeek<startingDay; dayOfWeek++)
printf(/*blanks*/);
for (int date = 1; date <= daysInMonth; date++) {
printf("…", date);
if (++dayOfWeek>6) {
printf("\n");
dayOfWeek = 0;
}
} // for date
if (dayOfWeek !=0)
printf("\n");
startingDay = dayOfWeek;
} // for month
}
Output:
February 2009
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
The following compiles, but there are still opportunities for improvement:
/* calender.c */
#include <stdio.h>
#include <stdlib.h>
#define JULIAN 1
#define GREGORIAN 2
/*
* return the day of the week for particualr date
* flag JULIAN or GREGORIAN
* (the divisions are integer divisions that truncate the result)
* Sun = 0, Mon = 1, etc.
*/
int get_week_day(int day, int month, int year, int mode) {
int a, m, y;
a = (14 - month) / 12;
y = year - a;
m = month + 12*a - 2;
if (mode == JULIAN) {
return (5 + day + y + y/4 + (31*m)/12) % 7;
}
return (day + y + y/4 - y/100 + y/400 + (31*m)/12) % 7; // GREGORIAN
}
int main(void) {
int year, month, date;
int startingDay; /* of the week: init from user input*/
char *names[] = {"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
printf("Enter the year of your desired calendar: ");
scanf("%d", &year);
// could check whether input is valid here
startingDay = get_week_day(1, 1, year,GREGORIAN);
int months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
months[1] = 29;
for (month = 0; month < 12; ++month) {
const int daysInMonth = months[month]; /* set # of days */
int dayOfWeek, date;
printf("\n ------------%s-------------\n", names[month]); // month name
printf(" Sun Mon Tue Wed Thu Fri Sat\n"); // days of week
for (dayOfWeek = 0; dayOfWeek < startingDay; ++dayOfWeek)
printf(" ");
for (date = 1; date <= daysInMonth; ++date) {
printf("%5d", date);
if (++dayOfWeek > 6) {
printf("\n");
dayOfWeek = 0;
}
} // for date
if (dayOfWeek != 0)
printf("\n");
startingDay = dayOfWeek;
} // for month
return EXIT_SUCCESS;
}