Calendar program with array help C++

I need help trying to display a 5 x 7 calendar for each month and detecting if its a leap year. I cannot seem to figure out how to make my array work to display the days of the month nor determine how the first day of every month should appear.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;

void getCalendarInput (/*inout*/ int&);         // gets user input of year
bool isLeapYear (/*in*/ int);                   // check and return  truth value for leap year
int startDayInputYear (/*in*/ int );            // computes start day for input year
int numOfDaysInMonth (/*in*/ int,/*in*/ bool);  // returns number of days in month
void CalendarMonthHeader (/*in*/ int);          // prints header for each month
void printMonth (/*in*/int,/*in*/ int&);        // prints month days and sends out the first day of the next month
void whitespace (/*in*/int);                    // prints the specified amount of spaces or leading white spaces

int main()
{
    int year, month;

    getCalendarInput(year);
    CalendarMonthHeader(month);

    return 0;
}

void getCalendarInput (/*inout*/ int& year)
{
    int monthDays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int DaysNumWeek;
    int firstDayInCurrentMonth;
    int currentMonth = 1;
    int numDays, month;
    bool leap;
    string str; //maybe needed for input validation
    char choice;

    //prompt for input
    cout << "What year do you want a calendar for? ";
    cin >>year; // str?

    while(year < 0 || !cin)
    {
        cin.clear();
        cin.ignore(200, '\n');
        cout << "Invalid integer! Enter a value greater than 0!\n" << endl;
        cout << "What year do you want a calendar for? ";
        cin >>year;
    }

    CalendarMonthHeader(month);

   /* leap = isLeapYear(year); //function call returns bool truth value
                             //needed to determine number of days in month for leap and non leap year

    firstDayInCurrentMonth = startDayInputYear( year ); // function call returns start day.
                                                        // Days of week numbered 0 through 9 for Sunday through Saturday.

    cout<< year << " " << leap << " " << firstDayInCurrentMonth <<endl; //remove statement - used to test key variable values */
}

bool isLeapYear (/*in*/ int year)
{
    return   ((year%4==0) && (year%100 !=0))||(year%400==0);
}

int startDayInputYear (/*in*/ int year)
{
    int startday;
    int num1, num2, num3;
    num1 = (year - 1)/ 4;
    num2 = (year - 1)/ 100;
    num3 = (year - 1)/ 400;
    startday = (year + num1 - num2 + num3) %7;
    return startday;
}

int numOfDaysInMonth (/*in*/ int month,/*in*/ bool isLeapYear)
{
    int monthDays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(isLeapYear)
        monthDays[1] = 29;
    return monthDays[month];

}

void CalendarMonthHeader (/*in*/ int month)
{
    int year;
    int DaysNumWeek, day;
    int monthDays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    isLeapYear(year);

    for(month = 0; month < 12; ++month)
    {

    if(month == 0)
    {
        cout << "January \n";
    }

    if(month == 1)
    {
        cout << "February \n";
        numOfDaysInMonth(month,isLeapYear);
    }

    if(month == 2)
    {
        cout << "March \n";
    }

    if(month == 3)
    {
        cout << "April \n";
    }

    if(month == 4)
    {
        cout << "May \n";
    }

    if(month == 5)
    {
        cout << "June \n";
    }

    if(month == 6)
    {
        cout << "July \n";
    }

    if(month == 7)
    {
        cout << "August \n";
    }

    if(month == 8)
    {
        cout << "September \n";
    }

    if(month == 9)
    {
        cout << "October \n";
    }

    if(month == 10)
    {
        cout << "November \n";
    }

    if(month == 11)
    {
        cout << "December \n";
    }
    }

    whitespace(day);

    for (int mday = 0; mday < monthDays[month]; ++mday)
    {
        cout << setw(3) << mday + 1;
        DaysNumWeek++;
        if (DaysNumWeek == 7)
        {
            cout << "\n" << setw(3);
            DaysNumWeek = 0;
        }

    }
}

void printMonth (/*in*/int, /*in*/ int&)
{

}

void whitespace (/*in*/int day)
{
    for (int i = 0; i < day; i++)
    {
        cout << "  ";
    }
}
For a start use an array of 12 (or 13 because there is no month_name[0]) month_names. So if month_no = 2, say, month_name[2] = "February" and that can be shortened by taking the first 3 characters when required. That way all your if's are eliminated.

Do a similar thing with day_names.

Bottom line, get the computer doing the work. It will do it more reliably than you or I can if its given the right instructions :)

PS you can use <vector>'s or other STL containers if you like, if you know what that means. I don't care :)
Like this for instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>

using namespace std;

const int MONTHS_PER_YEAR = 12;

int main()
{
    string month_name[]
    {
        "no_name", "January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "Novemeber", "December"
    };
    
    for(int i = 1; i <= MONTHS_PER_YEAR; i++)
        cout << "Month no: " << '\t' << i << '-' << month_name[i] << '\n';
    
    return 0;
}
It looks to me like you misunderstand a few things.
- Local variables are local to a function, even if they have the same name. So the variable month in main() is a completely different variable from month in getCalendarInput().
- Local variables whose type is "plain old data," like int, char, long, char, basically anything that isn't a class, are not initialized. That means their initial value is whatever bits happen to be in the memory where the program puts them. You have to set their value before you use them.

Okay, some specifics:
Line 19: You're calling CalendarMonthHeader() with local variable month, which hasn't been set to anything.
Line 48, you're calling CalendarMonthHeader() with local variable month, which hasn't been set to anything.
Lines 19 and 48: you call CalendarMonthHeader() twice. I suggest you delete the call at line 48. getCalendarInput() should just get the calendar input.
Line 89: You're calling isLeapYear() with the local variable year, but that hasn't been set to anything.
Line 102: You're passing the address of the isLeapYear function, not the value that results from calling it.
Line 156: day hasn't been set.
Lines 26, 77, & 88: You have the wrong value for February. Also why are there 3 copies of this data?

Some advice:
- turn on warnings. Most of the issues I mentioned are caught by the compiler.
- Decide what each function should do, write a comment to that effect, and then do it. This code looks like you just added stuff as you went along and got confused about what's doing what. [edit: I see that you did that in the declaration section at the top]
- Test one piece of the code at a time.

You're actually pretty close. All the logic seems to be there, you just need to clean up the program flow to use it properly.
Last edited on
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>

using namespace std;

const int NO_MONTHS{12 + 1};
const int NO_DAYS{7};

int days_per_month[]
{
    0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

const string day_name[]
{
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
    "Saturday", "Sunday"
};

const string month_name[]
{
    "no_name", "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "Novemeber", "December"
};

void checkLeapYear (int year)
{
    if( ((year%4 == 0) && (year % 100 != 0)) || (year % 400 == 0) )
    {
        days_per_month[2] = 29;
    }
    else
    {
        days_per_month[2] = 28;
    }
}

void printCalendarMonth(int year, int month)
{
    checkLeapYear(year);
    
    cout
    << month << ' ' << month_name[month] << ' '
    << days_per_month[month] << '\n';
}

int main()
{
    int year{0};
    while
        (
         cout << "What year do you want a calendar for? " &&
         cin >> year &&
         year < 0
         )
    {
        cout << "Invalid year! Enter a value greater than 0!\n";
    }
    
    for(int month_no = 1; month_no < NO_MONTHS; month_no++)
    {
        printCalendarMonth(year, month_no);
    }
    
    return 0;
}
Hello Depressed,

I started working on this before I saw dhayden's response.

I do agree with dhayden a function should do one thing and do it well and either return something or as you did by passing the variable by reference.

To that end "main" should just direct the program to make use of the functions that you have.

By defining variables like int year{ 2020 }, month{}, startDay{};, which is a start, but not complete, you give the variables a value so by the time you would call the "printMonth" function all the variables that you will need have values and the print function can just print the month.

This is a rough idea of what I am talking about:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstdlib>

using namespace std;  // <--- Best not to use.
// The most recent post that is worth reading. http://www.cplusplus.com/forum/beginner/258335/

void getCalendarInput(int& year);         // gets user input of year
bool isLeapYear(/*in*/ int);                   // check and return  truth value for leap year
int startDayInputYear(/*in*/ int);            // computes start day for input year
int numOfDaysInMonth(/*in*/ int,/*in*/ bool);  // returns number of days in month
void CalendarMonthHeader(/*in*/ int);          // prints header for each month
void printMonth(/*in*/int,/*in*/ int&);        // prints month days and sends out the first day of the next month
void whitespace(/*in*/int);                    // prints the specified amount of spaces or leading white spaces

constexpr size_t MAXMONTHS{ 13 };

int main()
{
	constexpr int DAYS_IN_MONTH[MAXMONTHS] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	const std::string monthNames[MAXMONTHS]{ "", "January", "February", "March", "April", "May", "June",
		"July", "August", "September", "October", "Novemeber", "December" };

	bool leapYear{};
	int daysInMonth[MAXMONTHS]{};
	int year{ 2020 }, month{}, startDay{};

	std::copy(std::begin(DAYS_IN_MONTH), std::end(DAYS_IN_MONTH), std::begin(daysInMonth));
	
	//getCalendarInput(year);

	leapYear = isLeapYear(year);

	startDay = startDayInputYear(year);


	CalendarMonthHeader(month);

	return 0;
}

void getCalendarInput(/*inout*/int monthDays[], int& year)
{
	//prompt for input
	cout << "What year do you want a calendar for? (1582 to 3000): ";
	cin >> year;

	while ((year < 1582 || year > 3000) || !cin)
	{
		if (!std::cin)
		{
			cin.clear();
			cin.ignore(200, '\n');
			cout << "Invalid input! Must be a number.\n" << endl;
		}
		else if (year < 0)
		{
			cout << "Invalid integer! Enter a value of 1582 to 3000!\n" << endl;
		}

		cout << "What year do you want a calendar for? ";
		cin >> year;
	}
}

On line 9 I added the variable name. This is not required, but it does help. While on the subject and just in case the prototype must match the function definition.

Line 21 is in "main" so that you always a base to start with.

Lines 26 and 29 are designed to give you an array to use that you can make changes to. Looking ahead at some point yo may want to put most of "main" in a while or do/while loop to look at different years. This way you can reset the array for the days in a month back to February having 28 days before you start over/

For line 29 if you can not use this yer a simple for loop can replace it.

For line 22 "main" may not be the best place to define this array, but I put it there to give you an idea. This is probably better defined in the function that would need it, (maybe the "printMonth" function).

Lines 31 - 38 give you an idea of how to use your functions and how to use "main" to direct the program flow.

As dhayden said
You're actually pretty close. All the logic seems to be there, you just need to clean up the program flow to use it properly.


For the function "CalendarMonthHeader" there are several options here:
First the individual if statements would work better as
1
2
if(...)
else if(...)

Also reversing the order, putting "December" first, would mean that each time through the loop you will be checking less and less.

Second option is to use a switch instead of all the if/else if statements.

Third option would be to put an array, (line 22), in the print function and use that when printing the month. This could eliminate the "CalendarMonthHeader" function altogether.

The program is fun to work on. I will keep up with it and see what I can come up with.

Andy
Hello Depressed,

Am I to understand that you desired output should be something like this:

   January
      1 2  3  4
5 6 7 8 9 10 11
...

   February
...


Andy
Thank you everyone for the help, and yes Andy I was looking to make it output something like that.
Hello Depressed,

I did manage to get to this point:

    January  2020
--------------------
 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

    February  2020
--------------------
 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

    March  2020
--------------------
 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

    April  2020
--------------------
 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

    May  2020
--------------------
 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


But when it gets to May it need one extra week for the 31st.

From my previous code I put line 22 in the print function as it is the only place it is needed.

The for loops I used to print out the numbers could still use some work. If you search here you should find some good examples to help you.

Andy

Edit: typo.
Last edited on
I tried changing the original code only slightly. Here's the main() that I ended up with. I think this uses the functions as they are documented to work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
    int year, month, firstDayOfMonth;

    getCalendarInput(year);
    firstDayOfMonth = startDayInputYear(year);
    for (month = 1; month <= 12; ++month) {
        bool isLeap = isLeapYear(year);
        int days = numOfDaysInMonth(month, isLeap);
        CalendarMonthHeader(month);
        printMonth(days, firstDayOfMonth);
    }

    return 0;
}
For sure! Appreciate all the feedback.
1
2
3
4
5
const string day_name[]
{
    "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
    "Saturday", "Sunday"
};


...

1
2
    string day_one = day_name[startDayInputYear(year)- 1];
    cout << "Year " << year << " starts on a " << day_one << '\n';
Topic archived. No new replies allowed.