I am getting a bad access error while trying to find days between two dates given as a string. I found that the maximum number of days that my function will find is 1884 but I don't know why. The bad access error is in the a.find("/") function call.
Here is the code. Any help would be much appreciated, thanks.
int daysBetweenDates(string a, string b) {
if (a == b) {
return 0;
}
cout << a << endl;
int month = stoi(a.substr(0, a.find("/")));
a = a.substr(a.find("/")+1);
int day = stoi(a.substr(0, a.find("/")));
a = a.substr(a.find("/")+1);
int year = stoi(a);
int k = 0; // days in the month;
if (month == 2) {
k = year%4==0 ? 29 : 28;
}
else if ((month == 4) || (month == 6) || (month == 9) || (month == 11)) {
k = 30;
}
else {
k = 31;
}
day++;
if (day > k) {
month++;
day = 1;
}
if (month > 12) {
year++;
month = 1;
}
string new_a = to_string(month) + "/" + to_string(day) + "/" + to_string(year);
return 1 + daysBetweenDates(new_a, b);
}
The recursive calls are eventually causing a stack overflow. Change the code to remove the potentially deeply nested calls. For example, by changing the routine to use a loop. C++ compilers typically do not do tail recursion optimization.
Related
when the first date is bigger than the second, it doesent calculate.
for example: first date 22/10/2022
second date: 15/10/2022
#include <iostream>
#include <cstdlib>
using namespace std;
class Date {
public:
Date(int d, int m, int y);
void set_date(int d, int m, int y);
void print_date();
void inc_one_day();
bool equals(Date d);
int get_day() { return day; }
int get_month() { return month; }
int get_year() { return year; }
private :
int day;
int month;
int year;
};
bool is_leap_year(int year)
{
int r = year % 33;
return r == 1 || r == 5 || r == 9 || r == 13 || r == 17 || r == 22 || r == 26 || r == 30;
}
int days_of_month(int m, int y){
if (m < 7)
return 31;
else if (m < 12)
return 30;
else if (m == 12)
return is_leap_year(y) ? 30 : 29;
else
abort();
}
void Date::inc_one_day(){
day++;
if (day > days_of_month(month, year)) {
day = 1;
month++;
if (month > 12) {
month = 1;
year++;
}
}
}
bool Date::equals(Date d) {
return day == d.day && month == d.month && year == d.year;
}
int days_between(Date d1, Date d2){
int count = 1;
while (!d1.equals(d2)){
d1.inc_one_day();
count++;
}
return count;
}
Date::Date(int d, int m, int y){
cout << "constructor called \n";
set_date(d, m, y);
}
void Date::set_date(int d, int m, int y){
if (y < 0 || m < 1 || m>12 || d < 1 || d > days_of_month(m, y))
abort();
day = d;
month = m;
year = y;
}
void Date::print_date(){
cout << day << '/' << month << '/' << year<<endl;
}
int main(){
Date bd(22, 12, 1395);
Date be(15, 12, 1395);
cout << '\n';
int i;
i= days_between(bd, be);
cout << i << endl;
}
here's my code.
I've seen many codes that calculate the days between two dates, but they didn't use class Date.
how can i solve this problem? could you guys help me please.I'm sorry i'm new in c++ so, my problem might be so basic.
It is clear why your algorithm does not work - you are incrementing the later date so it will never equal the earlier date. The solution is simply to compare the dates and swap the operands if necessary so that you are always incrementing the earlier date toward the later date.
int days_between(Date d1, Date d2)
{
int count = 0 ;
// Initially assume d2 >= d1
Date* earlier = &d1 ;
Date* later = &d2 ;
// Test if d1 > d2...
int year_diff = d2.get_year() - d1.get_year() ;
int mon_diff = d2.get_month() - d1.get_month() ;
int day_diff = d2.get_day() - d1.get_day() ;
if( year_diff < 0 ||
(year_diff == 0 && (mon_diff < 0 || (mon_diff == 0 &&
day_diff < 0 ))))
{
// d1 > d2, so swap
earlier = &d2 ;
later = &d1 ;
}
while (!earlier->equals(*later))
{
earlier->inc_one_day();
count++;
}
return count;
}
Note that it is not clear why you start with a count of 1. If the dates start equal, surely that should return a zero? That is how I have written it in any case.
If it is required to indicate whether the dates were reversed or not, you might want to return a signed value. In that case:
return earlier == &d2 ? -count : count ;
Which for the dates in your example will return -7.
Your solution is a good candidate for operator overloading so you could simply and more intuitively write:
if( d1 > d2 )
{
earlier = &d2 ;
later = &d1 ;
}
while( *earlier != *later))
{
earlier++ ;
count++ ;
}
return earlier == &d2 ? -count : count ;
and even ultimately:
i = be - bd;
What would be easier is to write a function that calculates the total number of days that have occurred since the year 0000. After that you can simply subtract them from each other and return the total number of days between them.
I want to solve this with recursion, but I am having trouble figuring out whats wrong. Create a function where given n days as an argument, return the total amount of items received throughout Christmas days as an integer.
xmasItems(1) = 1
xmasItems(3) = 10 : Day1 = (1), Day2 = (1+2), Day3 = (1+2+3) | Day 3 total = (1)+ (1+2) + (1+2+3) = 10
int xmasItems(int n) {
if (n == 0) { return 0; }
else {
int forThatDay = 0;
while (n != 0) {
forThatDay += n;
n--;
}
return forThatDay + xmasItems(n - 1);
}
}
In the while loop of your else branch, you are decrementing n all the way to 0. So you are computing only the first day's value.
Instead, you could use a copy of n for the forThatDay calculation, so you can make the recursive call correctly:
int xmasItems(int n) {
if (n == 0) { return 0; }
else {
int forThatDay = 0;
int m = n; // copy n and use it
while (m != 0) {
forThatDay += m;
m--;
}
return forThatDay + xmasItems(n - 1); // now n is correct
}
}
Aside: there is a closed form solution for the sum of n natural numbers, so you shouldn't need a loop anyway.
This project I'm working on is forcing me to use Visual C++-6.0 and it seems like everytime I compile this code it causes errors in not only this segment of code but elsewhere that is unrelated to this portion.
Right now I am trying to calculate an expiration date that is 15 months from the date that would be given.
I've tried researching if this is a common issue after windows updates. I know 6.0 has been unsupported and phased out but its a "requirement" for this program. I swore it was working 2 months ago and since that point about 30 patches have been deployed to my Windows 10 device.
Currently in this snippit of code the date that is passed into the code is carried through unaltered. For example: Nov-01-2019 should become Feb-01-2021
void CalculateDates(int numIndex)
{
int tDay = 0, tMonth = 0, tYear = 0, exp_Months = 15;
char sTemp1[4], sTemp2[4], sTemp3[4], sTemp4[4], sDay[4], sYear[4], *p;
p = Database[numIndexCount].sIdentifier;
strncpy(Database[numIndexCount].sPreparedBy, Database[numIndexCount].sIdentifier, 3);
Database[numIndexCount].sPreparedBy[3] = 0;
strncpy(sTemp1, p + 3, 2);
sTemp1[2] = 0;
strncpy(sTemp2, p + 5, 2);
sTemp2[2] = 0;
strncpy(sTemp3, p + 7, 2);
sTemp3[2] = 0;
strcpy(sTemp4, "20");
SetDateMonth(sTemp1);
sprintf(Database[numIndex].sPreparedDate, "%s-%s-%s%s", sTemp2, sMonth1, sTemp4, sTemp3);
tDay = atoi(sTemp2);
tMonth = atoi(sTemp1);
tYear = atoi(sTemp3);
if (tMonth <= 9) {
if (tMonth == 9) {
tMonth = 12;
tYear++;
// cout << "Is the month printing right? ";
// cout<<tMonth;
// cout << "\n";
}
else {
tMonth = (tMonth + exp_Months) % 12;
tYear++;
//cout << "Is the month printing right? ";
//cout<<tMonth;
//cout << "\n";
}
}
if (tMonth == 4 || tMonth == 6 || tMonth == 9 || tMonth == 11) {
// cout << "This is reached";
// cout << "\n";
// cout << "The day value is: ";
// cout << tDay;
// cout << "\n";
if (tDay == 31)
{
tDay = 30;
}
}
if (tDay >= 29 && tMonth == 2 && tYear % 4 == 0) {
if (tYear % 100 != 0) {
tDay = 29;
}
else if (tYear % 100 == 0 && tYear % 400 == 0) {
tDay = 29;
}
}
else if (tYear % 4 != 0 && tMonth == 2) {
tDay = 28;
}
sprintf(sTemp1, "%i", tMonth);
if (tDay < 10) sprintf(sDay, "0%i", tDay);
else sprintf(sDay, "%i", tDay);
if (tYear < 10) sprintf(sYear, "0%i", tYear);
else sprintf(sYear, "%i", tYear);
SetDateMonth(sTemp1);
sprintf(Database[numIndex].sUseByDate, "%s-%s-%s%s", sDay, sMonth1, sTemp4, sYear);
sprintf(sUseByDate, "%s-%s-%s%s", sDay, sMonth1, sTemp4, sYear);
}
End results for the above for today were Nov-01-19 but should have been Feb-01-19
I'm currently working on a project for my intro to C++ programming class. The project asks a user to enter a date using mm/dd/yyyy format. Based on the information given, the program then has to determine if the date is valid or invalid, then displays a response to that. I'm facing the problem currently where everything is coming out reading "Good date!" I'm not sure where the problem is. Any help is appreciated. If you could help point me in the right direction, that would be awesome.
#include <iostream>
#include <conio.h>
using namespace std;
void getDate(int *month, int *day, int *year);
int checkDate(int month, int day, int year);
void displayMessage(int status);
int main()
{
int month, day, year;
int s = 0;
getDate(&month, &day, &year);
do
{
checkDate(month, day, year);
displayMessage(s);
getDate(&month, &day, &year);
}
while (_getch() != EOF);
}
void getDate(int *month, int *day, int *year)
{
char fill;
fill = '/';
cout << "Enter a date in mm/dd/yyyy form: ";
cin >> *month;
if (cin.get() != '/')
{
cout << "expected /" << endl;
}
cin >> *day;
if (cin.get() != '/')
{
cout << "expected /" << endl;
}
cin >> *year;
cout << *month << fill << *day << fill << *year << endl;
};
int checkDate(int month, int day, int year)
{
if ((month = 1) || (month = 3) || (month = 5) || (month = 7) ||
(month = 8) || (month = 10) || (month = 12))
{
day <= 31;
}
else if ((month = 4) || (month = 6) || (month = 9) || (month = 11))
{
day <= 30;
}
else if ((month = 2) && (year % 4 == 0))
{
day <= 29;
}
else if ((month = 2) && (year % 4 != 0))
{
day <= 28;
};
int status = 0;
if ((year < 999) || (year > 10000))
{
status == 1;
}
if ((month < 1) || (month > 12))
{
status == 2;
}
else if ((day < 1) || (day > 31))
{
status == 3;
}
else if ((day < 1) || (day > 30))
{
status == 4;
}
else if ((day < 1) || (day > 29))
{
status == 5;
}
else if ((day < 1) || (day > 28))
{
status == 6;
}
return status;
};
void displayMessage(int status)
{
if (status == 0)
{
cout << "Good date!" << endl;
}
if (status == 1)
{
cout << "Bad year" << endl;
}
if (status == 2)
{
cout << "Bad month" << endl;
}
if (status == 3)
{
cout << "Bad day. Not 1-31" << endl;
}
if (status == 4)
{
cout << "Bad day, not 1-30" << endl;
}
if (status == 5)
{
cout << "Bad day, not 1-29" << endl;
}
if (status == 6)
{
cout << "Bad day, not 1-28" << endl;
}
_getch();
}
1) There are a couple of issues here, but the most obvious one is in main():
int s=0;
...
checkDate(month, day, year); // you don't store the status
displayMessage(s); // so s will always be 0 ! So good date !
You have to correct this:
s=checkDate(month, day, year); // store the result of the check
displayMessage(s); // and take it to display the message
2) Then in checkDate(), you mixup = and ==. = changes the value of the variable to its left. == just makes a comparison but store nothing. When correcting/adjusting, without any optimisation, your code should look like:
int checkDate(int month, int day, int year)
{
int status=0;
if ((month == 1 || month == 3 || month == 5 || month == 7 ||
month == 8 || month == 10 || month == 12) && ( day>31 || day<1) )
{
status = 3;
}
else if ((month == 4 || month == 6 || month == 9 || month == 11) && (day>30 || day<1) )
{
status = 4;
}
else if ((month == 2) && (year % 4 == 0) && (day>29 || day<1))
{
status = 5;
}
else if ((month == 2) && (year % 4 != 0) && (day>28 || day<1) )
{
status = 6;
}
else if ((year < 999) || (year > 10000))
{
status = 1;
}
if ((month < 1) || (month > 12))
{
status = 2;
}
return status;
};
3) After this, you should improve the input function, because:
it doesn't cope with invalid separators. If '/' are missing, an error message is displayed, but you continue the input as if everything was fine.
it doesn't cope with invalid (i.e.non numeric) input. If user enters XI/1/2016 for example, your input will fail.
So keep in mind that (cin>>xxx) is an expression that you could use in an if and is true if everything was read correctly. Also be aware that cin.clear() clears error flags that blocks input after a failure.
You also could make use of the function mktime().
It tries to convert a given tm struct into a correct date. If the comparison of the individual members of the struct subsequently shows equality for all members, the given tm struct contained a valid date.
bool CBorrow::validateDate(tm * timestruct)
{
struct tm copy;
copy.tm_sec = timestruct->tm_sec;
copy.tm_min = timestruct->tm_min;
copy.tm_hour = timestruct->tm_hour;
copy.tm_mday = timestruct->tm_mday;
copy.tm_mon = timestruct->tm_mon;
copy.tm_year = timestruct->tm_year;
copy.tm_wday = timestruct->tm_wday;
copy.tm_yday = timestruct->tm_yday;
copy.tm_isdst = timestruct->tm_isdst;
time_t res = mktime(©);
if (res < 0)
{
return false;
}
if (copy.tm_mday != timestruct->tm_mday
|| copy.tm_mon != timestruct->tm_mon
|| copy.tm_year != timestruct->tm_year)
{
return false;
}
return true;
}
Updated answer for C++20:
#include <chrono>
#include <iostream>
void
displayMessage(std::chrono::year_month_day ymd)
{
using namespace std;
using namespace std::chrono;
if (!ymd.year().ok())
{
cout << "Bad year\n";
return;
}
if (!ymd.month().ok())
{
cout << "Bad month\n";
return;
}
if (!ymd.ok())
{
cout << "Bad day, not 1-" << (ymd.year()/ymd.month()/last).day() << '\n';
return;
}
cout << "Good date!\n";
}
int
main()
{
using namespace std::literals;
displayMessage(29d/2/1900);
}
Output:
Bad day, not 1-28
(1900 was not a leap year)
Can this also be achieved by a regular expression?
I know there are many drawbacks in this approach, but still may be considered:
#include <regex>
#include <string>
using std::regex;
using std::regex_match;
using std::string;
// for ddmmyy
regex ddmmyy("^([0-2][0-9]|(3)[0-1])(((0)[0-9])|((1)[0-2]))\\d{2}$");
/*
for dd/mm/yy https://regex101.com/r/IqPLBJ/1
for dd/mm/yyyy - could start from \\d{4}$ instead of \\d{2}$ bearing 0000-case in mind
*/
regex slashed_ddmmyy("^([0-2][0-9]|(3)[0-1])\/(((0)[0-9])|((1)[0-2]))\/\\d{2}$");
string f1 = "111223";
bool res = regex_match(f1,ddmmyy); // true
f1 = "112223";
res = regex_match(f1,ddmmyy); // false
res = regex_match(f1, slashed_ddmmyy); // false, no slashes
A more compact and stripped checkDate (replace uppercase return by value)
int checkDate(int day, int month, int year) {
if(day < 1 || day > 31) {
return BADVALUE;
} else if(month < 1 || month > 12) {
return BADVALUE;
} else if (year < MINYEAR || year > MAXYEAR) {
return YEAROUTRANGE;
}
if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
return BADMONTHDAY;
} else if ((month == 2) && (year % 4 == 0) && day > 29) {
return BADMONTHYEAR;
} else if ((month == 2) && (year % 4 != 0) && day > 28) {
return BADMONTHYEAR;
}
return GOOD;
}
I'm trying to solve problem that asks to find how many times 13th day occurs at each weekday in period of 1990+N-1 years.
int weekDay = 1;
int week[] = {0,0,0,0,0,0,0};
N = 20;
for (int year = 1990; year <= 1990+N-1; year++){
for (int month = 1; month <= 12; month++){
int days = numberOfDays(year,month);
for (int day = 1; day <= days; day++){
if (day == 13)
week[weekDay] += 1;
weekDay += 1;
if (weekDay > 7)
weekDay = 1;
}
}
}
Here's my solution, however I get stuck in an infinite loop in year and can't seem to fix it.
EDIT : numberOfDays function.
int numberOfDays(int year, int month)
{
if (month == 2 && leapYear(year))
return 29;
else if (month == 2)
return 28;
if (month == 9 || month == 4 || month == 6 || month == 11)
return 30;
return 31;
}
You are using weekdays in the range 1..7 but your histogram array week[] is indexed 0..6.
One possible solution - change:
week[weekDay] += 1;
to:
week[weekDay - 1] += 1;
Another solution - make week[] one element bigger and don't use element 0, i.e. change:
int week[] = {0,0,0,0,0,0,0};
to:
int week[] = {0,0,0,0,0,0,0,0};
A third possible solution - use week days in the range 0..6, i.e. change:
int weekDay = 1;
to:
int weekDay = 0;
and change:
if (weekDay > 7)
weekDay = 1;
to:
if (weekDay > 6)
weekDay = 0;
Off-by-one. Your week[] array has 7 elements, indexed 0..6. You write to week[7], which overwrites something you didn't intend, such as e.g. the year variable.