How i make restrictions into a variable - c

I'm new in C language and I have a question.
I have to create a program where I put the number of days I worked in every single month.
I already done that but I need to restrict the days by the number of days of each month .
Example : January more than 1 day less than 31 , February more than 1 but less than 28 etc...
int numero_dias, mes;
for (mes = 0; mes != 12; mes++){
do {
printf("Digite o
numero de dias trabalhados no mes %s: ", meses[mes]);
scanf("%d", &numero_dias);
if (meses[mes] == 0 meses[mes] == 2 meses[mes] == 4 meses[mes] == 6 meses[mes] == 7 meses[mes] == 9 meses[mes] == 11 ){
if (numero_dias < -1 || numero_dias > 31){
continue;
}else{
break;
}
}

If I understand your question correctly, you want to:
Enter the number of days you worked in a month;
Check that the number of days you entered does not exceed the number of days for that month.
So, if you're entering the number of days you worked for the month of January, that number has to be between 0 and 31 (I'm assuming it's possible you can work zero days in a month). For the month of February it has to be between 0 and 28 (29 in a leap year), for April it has to be between 0 and 30, etc.
An easy way to do this is to set up an array to keep track of the number of days per month, indexed by the month number (0 for January, 1 for February, etc.):
/**
* We're declaring this const so that we can't accidentally change any
* of the entries in the array.
*/
const int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
We'll have to add some special-case processing for February to deal with leap years, but for this first pass we won't worry about it.
It may also be useful to have another array1 for the month names, since you try to display that in your loop:
const char *names[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
So now your loop becomes:
for (mes = 0; mes < 12; mes++ )
{
do
{
printf( "Digite o numero de dias trabalhados no mes %s: ", names[mes] );
scanf ( "%d", &numero_dias );
} while ( numero_dias < 0 || numero_dias > days[mes] );
// do something with numero_dias
}
The inner do loop will repeat while numero_dias is outside the range of 0 and days[mes]. So when mes is 0, days[mes] is 31, when mes is 3, days[mes] is 30, etc.
February (1) is a special case - it can be either 28 or 29 days. So we need to modify the condition of the do loop slightly:
do
{
...
} while ( numero_dias < 0 || numero_dias > ( mes != 1 ? days[mes] : feb_days() ) );
The expression mes != 1 ? days[mes] : feb_days() checks to see if mes corresponds to February (1) - if it doesn't, then we use the value in days[mes] (January, March, April, May, etc.). If it does, then we call another function feb_days() that returns the number of days in February for the current year.
So the condition in the do-while loop now checks to see if numero_dias is less than zero or greater than the number of days for the current month, with a special case for February.
To get the number of days in February for the current year, you can do the following:
int feb_days( void )
{
time_t now = time( NULL ); // Get number of seconds since 1970-01-01
struct tm *utc = gmtime( &now ); // Break time into year, month, day, etc.
int days = 28; // default number of days in Feb
return days + (utc->tm_year % 4 == 0 && (utc->tm_year % 100 != 0 || utc->tm_year % 400 == 0 ));
}
The expression (utc->tm_year % 4 == 0 && (utc->tm_year % 100 != 0 || utc->tm_year % 400 == 0 )) will evaluate to 1 if the current year is divisible by 4 and it's not divisible by 100 or it is divisible by 400. If any of those conditions are not true, then it evaluates to 0. So if this is not a leap year, we return 28 + 0 == 28 days. If it is a leap year, we return 28 + 1 == 29 days.
There's a lot more bulletproofing that needs to be done - you need to check the return value of scanf to make sure your input was actually read correctly (and take action to clear the input stream if it wasn't), you probably want to give your user a way to cancel the input operation, etc., but this should get you started.
Actually, we'd use a single array of a struct type instead of separate arrays, but I'm trying to keep things basic.

Related

How to calculate how many days to the person's birthdate from the beginning of their birthyear in C?

This us how much I've gotten
int myd;
int mym;
int myy;
printf("Enter your day of birth:");
scanf("%d", &myd);
printf("Enter your month of birth:");
scanf("%d", &mym);
printf("Enter your year of birth:");
scanf("%d", &myy);
int month;
if (mym == 1 || mym == 3 || mym == 5 || mym == 7 || mym == 8 || mym == 10 || mym == 12)
{month = 31;}
else if (mym == 4 || mym == 6 || mym == 9 || mym == 11)
{month = 30;}
else if (mym == 2 && myy %4 !=0 && myy %100 ==0)
{month = 28;}
else if (mym == 2 && myy %4 ==0 && myy %100 !=0)
{month = 29;}
I'm not sure how to increment the days of the months before the birth month.
If I knew that, maybe I can add that increment + birth date = no. of days until birthday from the beginning of their birth year
You need an array, which contains a number of days in each month. Each element beside the 2nd one will have a literal value, either 30 or 31:
int days_in_month[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
For the 2nd element, representing February, you need to calculate the number of days based on the year. You already have that, but it is not correct. For example this condition:
... && myy % 4 != 0 && myy % 100 == 0)
will never be true. Even after after changing the operator:
... && (myy % 4 != 0 || myy % 100 == 0))
it is still not correct because it will match years divisible by 400, which are leap years. The correct condition is:
(myy % 4 != 0 || myy % 100 == 0) && myy % 400 != 0
or for leap years (basically a negation of the above):
(myy % 4 == 0 && myy % 100 != 0) || myy % 400 == 0
With that, the rest is just a loop through days_in_month, summing the values of days in months previous to the birthday, and at the end adding the day of month of the birthday. You can see the code in godbolt. The output of some examples:
]$ echo -en "1\n3\n1900\n" | ./a.out
Enter your day of birth:Enter your month of birth:Enter your year of birth:
01-03-1900: 60
]$ echo -en "1\n3\n1996\n" | ./a.out
Enter your day of birth:Enter your month of birth:Enter your year of birth:
01-03-1996: 61
]$ echo -en "1\n3\n1997\n" | ./a.out
Enter your day of birth:Enter your month of birth:Enter your year of birth:
01-03-1997: 60
]$ echo -en "1\n3\n2000\n" | ./a.out
Enter your day of birth:Enter your month of birth:Enter your year of birth:
01-03-2000: 61
As a last point, one could argue that a year starts with Jan 1st, so there is 0 days from the beginning of the year to Jan 1st :-) If that's the case, just subtract 1 from the final result.
EDIT
One more thing, before doing any calculations, validate user inputs first. In particular that the month is between 1 and 12 (inclusive), or otherwise you will start reading garbage past the days_of_month array.
You can use codes like this:
int mym;
int answer[] = {31,0,31,30,31,30,31,31,30,31,30,31};
printf("Enter your month of birth:");
scanf("%d", &mym);
if(mym==2){
if(myy %4 != 0 && myy %100 ==0){
answer[mym] = 28;
}
if(myy %4 ==0 && myy %100 !=0){
answer[mym]= 29;
}
}
else{
printf("%d",answer[mym]);
}
I think you should use array ( like answer[] ) for convenience.

return the day of the week with day, month, year and first of January provided?

I have the C99 as follow:
int dayOfWeek(int day, int month, int year, int firstJan);
The first parameter, day, provides the day of interest − range from 1 to 31 (inclusive). The second parameter, month, provides the month of interest − range from 1 to 12 (inclusive). The third parameter, year, provides the year of interest − any integer value of 1970 or greater. The fourth parameter, firstJan, indicates the day of the week on which the first of January falls in the provided year.
The function will return the day of the week on which the indicated date falls. For example, the call:
dayOfWeek(13, 11, 2017, 0);
will return the integer 1 (representing Monday).
How can I approach the solution? Its permitted values are 0 (representing Sunday), 1 (representing Monday), and so on, up to 6 (representing Saturday). Code has been edit:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int dayOfweek(int day, int month, int year, int firstJan)
5 {
6 int mth[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
7 int mth_leap[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
8
9 if(year <1970 || month < 1 || month > 12 || day < 1 || day > 31 || firstJan < 0 || firstJan > 6 ){
10 printf("invalid input");
11 //return -1;
12 }
13
14 if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)){
15 day = mth_leap[month - 1] + day ;
16 }else{
17 day = mth[month - 1] + day;
18 }
19
20 int dow = (day - firstJan + 7)%7;
21 printf("Day of week is %i.\n", dow);
22 //return 1;
23
24 }
Day of the week is found simply with mktime().
The mktime function
On successful completion, the values of the tm_wday and tm_yday components of the structure are set appropriately, and the other components are set to represent the specified calendar time,
#include <time.h>
int dayOfWeek(int day, int month, int year, int /*firstJan*/) {
// struct tm members domain are: years from 1900, and months since January
// Important to set tm_isdst = -1 to let the function determine dst setting.
struct tm ymd = { .tm_year - 1900, .tm_mon = month - 1, .tm_mday = day, .tm_isdst = -1);
time_t t = mktime(&ymd); // this will fill in .tm_wday
if (t == -1) return -1; // Failed to find a valid calender time (and day-of-the-week)
return ymd.tm_wday;
}
How can I approach the solution?
Yet OP has a function that provides the day-of-the-week for Jan 1st.
Some pseudo code for that approach:
int dayOfWeek(int day, int month, int year, int firstJan) {
days_since_jan1 = table[month] + day;
if (month > Feb and isleap(year)) days_since_jan1++;
dow = (days_since_jan1 - firstJan + 7)%7
}

An error with the logic in creating a basic calendar program

I made a program just for testing purposes, when you hold the key 'p' on the keyboard it spills out every day starting from the 1st of January 2012, it should continue on to 2013 and it does although it goes to 32 January 2013, and this is an error which I have no idea how to fix, I've been trying to fix this problem for a few hours now and nothing seems to make it work as it should.. (should go to 1st February 2013 after 31st of January)
here is my code:
#include <stdio.h>
#include <stdlib.h>
int month[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int day = 0;
int year = 2012;
char *months[]=
{
" ",
" January ",
" February ",
" March ",
" April ",
" May ",
" June ",
" July ",
" August ",
" September ",
" October ",
" November ",
" December "
};
int x = 1; //skip the blank element 0, get to January (element 1)
int main()
{
while(1)
{
char ch;
ch = getch(); //in_char();
if(ch == 'p')
{
day++;
if(day == month[x]+1)
{
day = 1; //day is equal to the first day of the new month
month[x]++; //month data increments
months[x]++; //month display increments
x++; //element of month array increments to get the data of the next month
if(year % 4 == 0) //leapyear
{
month[2] = 29;
}
else
{
month[2] = 28;
}
if(x == 13) //if 12 months have passed
{
year++; //year increments
day = 1; //initialize day to be day 1 of the next year
x = 1; //go back to the 'January' element in the array
if(day == month[x]) //if day is equal to the first month (January) 31 days
{
day = 1;
month[x]++; //month data increments
months[x]++; //month display increments
}
}
}
if(year == 9999)
{
year = 1;
}
printf("%i%s%04i\n",day,months[x],year);
}
}
return 0;
}
output:
.
.
.
28 December 2012
29 December 2012
30 December 2012
31 December 2012
1January 2013
2January 2013
3January 2013
4January 2013
5January 2013
6January 2013
7January 2013
8January 2013
9January 2013
10January 2013
11January 2013
12January 2013
13January 2013
14January 2013
15January 2013
16January 2013
17January 2013
18January 2013
19January 2013
20January 2013
21January 2013
22January 2013
23January 2013
24January 2013
25January 2013
26January 2013
27January 2013
28January 2013
29January 2013
30January 2013
31January 2013
**32January 2013**
1February 2013
2February 2013
.
.
.
The problem is here:
if(day == month[x]+1)
{
day = 1; // reset date...OKAY
month[x]++; // NOT OKAY
by doing month[x]++ you are incrementing the number of days allowed in the month. Instead you need to keep a variable to track the month,just as you've done with day and year..

Is there something wrong with my date code?

Description: given a date after START_GREGORIAN_CALENDAR, this function returns the number of days until the next Thursday. For example, for 16 March 2011 (2011,3,16), the function will return 1, and for 17 March 2011 (2011,3,17), the function will return 7.
int daysToNextThursday (int year, int month, int day) {
int Thursday;
Thursday = 7;
return (Thursday - day);
}
The code compiles correctly, but when I input a date, e.g. 16 3 2011, I do not get the right answer. Note this is apart of a larger amount of code that I have written, which works perfectly.
Any ideas?
Yes, I have an idea. My idea is that you go back and rethink the algorithm you've selected for determining that a day is Thursday. It's dead wrong :-)
Now, like a broken clock that's right twice a day, you may find input parameters that give you the correct answer but they'll be the exception rather than the rule.
If you want to figure out when next Thursday is from a given date, C provides date and time functions for exactly that purpose:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
static char *textday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
int main (int argc, char *argv[]) {
int year, month, day, today, thursday;
struct tm *mytm;
time_t mytime;
// Get all arguments (minimal error checks).
if (argc != 3) {
printf ("Usage: next_thursday <year> <month>\n");
return -1;
}
year = atoi (argv[1]);
month = atoi (argv[2]);
// Do first fourteen days of the month.
for (day = 1; day <= 14; day++) {
Up until there, it's just getting parameters and starting the loop. The meat of the calculation is below, setting up a useful struct tm and then forcing our year, month and day into it. Then mktime will fill in the tm_wday (day of week) field for us and we can use that to figure out the number of days till Thursday.
// Make the tm structure based on date (and midday).
mytime = time (0);
mytm = localtime (&mytime);
mytm->tm_year = year - 1900;
mytm->tm_mon = month - 1;
mytm->tm_mday = day;
mytm->tm_hour = 12;
mytime = mktime (mytm);
// Output filled in fields and days till next Thursday.
today = mytm->tm_wday;
thursday = (11 - today) % 7;
if (thursday == 0)
thursday = 7;
printf ("%04d-%02d-%02d, weekday = %d (%s), days till Thu = %d\n",
mytm->tm_year + 1900, mytm->tm_mon + 1, mytm->tm_mday,
today, textday[today], thursday);
}
return 0;
}
Note that the thursday calculation is a bit of modulus trickery - it's simply used to give us the number of days based on the following table:
today thursday
------- --------
0 (sun) 4
1 (mon) 3
2 (tue) 2
3 (wed) 1
4 (thu) 7
5 (fri) 6
6 (sat) 5
If you want a more readable solution, you can use:
if (today < 4) thursday = 4 - today;
else thursday = 11 - today;
This program outputs the following for 2011-03:
2011-03-01, weekday = 2 (Tue), days till Thu = 2
2011-03-02, weekday = 3 (Wed), days till Thu = 1
2011-03-03, weekday = 4 (Thu), days till Thu = 7
2011-03-04, weekday = 5 (Fri), days till Thu = 6
2011-03-05, weekday = 6 (Sat), days till Thu = 5
2011-03-06, weekday = 0 (Sun), days till Thu = 4
2011-03-07, weekday = 1 (Mon), days till Thu = 3
2011-03-08, weekday = 2 (Tue), days till Thu = 2
2011-03-09, weekday = 3 (Wed), days till Thu = 1
2011-03-10, weekday = 4 (Thu), days till Thu = 7
2011-03-11, weekday = 5 (Fri), days till Thu = 6
2011-03-12, weekday = 6 (Sat), days till Thu = 5
2011-03-13, weekday = 0 (Sun), days till Thu = 4
2011-03-14, weekday = 1 (Mon), days till Thu = 3

Correctness of Sakamoto's algorithm to find the day of week

I am using Sakamoto's algorithm to find out the day of week from a given date.
Can anybody tell me the correctness of this algorithm? I just want this from 2000 to 2099.
The algorithm from Wikipedia is given for reference.
int dow(int y, int m, int d)
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
Well, you can tell just by looking at it that it is correct... Assuming that the t[] array is correct, which you can verify with just 12 spot checks (one for each month using any day/year).
The y -= m < 3 is a nice trick. It creates a "virtual year" that starts on March 1 and ends on February 28 (or 29), putting the extra day (if any) at the end of the year; or rather, at the end of the previous year. So for example, virtual year 2011 began on Mar 1 and will end on February 29, while virtual year 2012 will begin on March 1 and end on the following February 28.
By putting the added day for leap years at the end of the virtual year, the rest of the expression is massively simplified.
Let's look at the sum:
(y + y/4 - y/100 + y/400 + t[m-1] + d) % 7
There are 365 days in a normal year. That is 52 weeks plus 1 day. So the day of the week shifts by one day per year, in general. That is what the y term is contributing; it adds one to the day for each year.
But every four years is a leap year. Those contribute an extra day every four years. Thanks to the use of virtual years, we can just add y/4 to the sum to count how many leap days happen in y years. (Note that this formula assumes integer division rounds down.)
But that is not quite right, because every 100 years is not a leap year. So we have to subtract off y/100.
Except that every 400 years is a leap year again. So we have to add y/400.
Finally we just add the day of the month d and an offset from a table that depends on the month (because the month boundaries within the year are fairly arbitrary).
Then take the whole thing mod 7 since that is how long a week is.
(If weeks were eight days, for example, what would change in this formula? Well, it would be mod 8, obviously. Also the y would need to be 5*y, because 365 % 8 == 5. Also the month table t[] would need adjusting. That's it.)
Incidentally, Wikipedia's statement that the calendar is "good until 9999" is totally arbitrary. This formula is good for however long we stick with the Gregorian calendar, whether that is 10 years, 100 years, 1000 years, or 1 million years.
[edit]
The above argument is essentially a proof by induction. That is, assuming that the formula works for a particular (y,m,d), you prove that it works for (y+1,m,d) and (y,m,d+1). (Where y is a "virtual year" starting March 1.) So the key question is, does the sum change by the correct amount as you move from one year to the next? With knowledge of the leap year rules, and with the "virtual year" having the extra day at year end, it trivially does.
Recently I wrote blog post about this algorithm here.
The basic idea behind algorithm is to for February and January to count day
of week from 31 Dec of the previous year. For all other months we will be counting day of week from current year 31 Dec. We do this in two
steps first we compute day of week of last day of month preceding current month m then we just add d modulo seven.
31 Dec 1 BC is Sunday that is encoded as 0, Monday is 1 etc.
So we have: 0 + y + y/4 - y/100 + y/400 this with y -= m < 3 computes
day of week of 31 Dec of current year or previous year (depending on month). Note: 365 % 7 == 1 this explains why we wrote y instead of 365*y. The last component d is obvious since we start counting day of week from previous month last day.
The last part that need to be explained are values in array, for first two values these are number of days since last year 31 Dec to start of the month % 7. For rest of the months they are negated modulo seven number of days from end of prev month to 31 Dec of the current year. In other words we are subtracting days by addition modulo 7 e.g. (a-b)%7 = (a+(7-b%7))%7.
More explanation you may find in my blog post.
This might not be a complete answer like some mentioned above, But just would like to add one thing regarding this array : 0 3 2 5 0 3 5 1 4 6 2 4
Consider months beginning from March and ending at February just like others said:
March
April
May
June
July
August
September
October
November
December
January
February
Writing January to December from above numbering style :
So consider this as an array :
int t[] = {11,12,1,2,3,4,5,6,7,8,9,10};
Now for all elements in array just do : (2.6*m - 0.2) mod 7
parse the result as integer and you will get this:
0 3 2 5 0 3 5 1 4 6 2 4
You can find this formula here : wikipedia
int dayOfWeek(int d, int m, int y){
// Months Array
int t[] = {11,12,1,2,3,4,5,6,7,8,9,10};
// Convert months array
for (int i = 0; i < 12; i++){
int ans = t[i] * 2.6 - 0.2;
t[i] = ans % 7;
}
// Continue Algo
if(m<3)
y -= 1;
int day = (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
return day;
}
this : + y/4 - y/100 + y/400 is related to leap year. The algo to check for leap year is :
Perfectly Divisible by 400 -> true
IF perfectly divisible by 100 but not by 400 -> False
Divisible by 4 -> True
perform checks on above order. Maybe that is why they subtracted y/100 and added y/4 & y/400. Yeah silly logic 😅
I know this might not be the answer, But this might help to those who find it difficult to remember/understand stuff, yeah! not all of us have high IQ levels of understanding stuff and sadly some of us can't remember stuff too, lol.
For Gregorian Calendar
int dayToWeekG(int d,int m,int y){
int i;
int t[12]={0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
//{0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
y-=m<3;
i=(y+y/4-y/100+y/400 +t[m-1]+d)%7;
return i;
}
Explanation:
See the commented array for
t[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
and compare it with a calendar of a whole year (run cal 2to generate calendar in terminal in linux/unix) notice the starting day of the week of the day for each month.
Every normal year shifting one day of the week and leap year shifting two days of the week. as (365%7)=1 and (366%7)=2
i= y+y/4-y/100+y/400
But we are should not calculate the extra day if y is a leap year for month 0 and 1
y-=m<3
but by this way we are also removing the extra day from non-leap years too. so we will fill up the gap by subtracting 1 day for every month after February.
int t[12]={0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};

Resources