I am trying to make a program inside a class and add to the date one in each.
So if the date was: 1/1/2014 I want it to be 2/2/2015.
I was able to figure out the part for the day and the month, however, for some reason I am getting a strange number for the year.
when I tried to debug the program I found out that it's printing the following
1/1/2014
1/1/2014
1/0/2014 // I am not sure why did it change the day to 0 but I don't care about this as I'm getting the correct result at the end
2/2/4028 // I am more concern about the 4028 ! I don't know from where did this come from
2/2/4028
Here is what I've done so far:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class Date
{
public:
int day, year, monthnum;
Date(int d=1, int m2 =1, int y= 2014)
{
monthnum = m2;
day = d;
year =y;
cout << *this; // this is just for testing purposes
}
Date operator+(const Date&) const;
friend ostream& operator << (ostream& out, const Date& date)
{
out << date.monthnum << "/" << date.day << "/" << date.year <<endl;
return out;
}
};
Date Date:: operator+(const Date& date) const
{
return Date(day+date.day,monthnum+ date.monthnum ,date.year+year); // I think there is something with the "date.year + year" because when I remove this I get my initialization of the year which is 2014, however, I need it to be 2015 when I add one to it.
}
void testprogram()
{
Date date1(1), date2(1), date3(0);
date3 = date1 + date2;
cout << date3 << endl;
}
int main()
{
testprogram();
return 0;
}
Think carefully about what a Date represents, and what adding things to Dates would mean. A Date is a particular point in time. Adding them together would be like adding the latitude and longitude of Denver and Cleveland together and expecting the coordinate to mean something useful!
Your default parameters specify the year to be 2014, so when you add date1 and date2 you get date3.year = 2014 + 2014. I would caution you to avoid default parameters except in cases where the caller will almost always want the default. It's throwing you off for date3 as well, because you're specifying that day=0, monthnum=1, year=2014.
return Date(day+date.day,monthnum+ date.monthnum ,date.year+year);
Here you are adding each year, month and day of date1 to date2. So 2014 + 2014 = 4028!
if you're trying to add "1" to each part, write a function to return monthnum + 1, day + 1 and year + 1.
Related
In class where we learn C++, I was given an assignment to make a class "date". Now, there is a specific function that I am required to make but I really do not have idea how to approach this. Members of class are day, month and year. Function takes some integer that represents days, and is supposed to set a new date, that comes after that many days. For example, if date is (DD-MM-YY) 20.01.2015, and we pass as an argument 15, new date is 04.02.2015, the problem is that I have to consider how many days each month has(considering February has 28 days), and if argument is too big, that we pass into next year, create an exception that prints how many days are there until next year(considering year has 365 days). That is, if the date is 20.12.2010, and argument is greater than 11, it should print 11.
My attempt was using while, where I declared at the beginning that int k=0; and where argument of function is a, than I used while(k!=a), but body of the function got really confusing because I used just too many if conditions. Another thing that I tried is to overlap operator++ and that surely gives me simpler function, because than there is only one for loop inside it, but I am not solving the problem, because in that overlapped operator function I am still using many if conditions.
Is there some elegant way to do this? Code and explanation would be great! Thank you!
Simply identify what you need and then create it, like
static unsigned int Date::days_of_month(const Month month, const unsigned int year);
void Date::operator+=(const unsigned int days);
+= could look like
void Date::operator+=(const unsigned int days){
increase current day by days
check if current day too large
if so, increase month (and maybe year)
repeat until day legal
}
Concept is clear? Haven't build in your output on purpose to give you something to do, after all, it's an exercise. Also wrote this in pseudo-code on purpose for the same reason. Try to create some code and if you really can't proceed, I'll add actual code.
const int m_daysInMonth[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; // first for index offset (no "zero" month)
class date {
public:
int days=20, month=11, year=2012;
void addDays(int daysNum)
{
int n_days = days, n_month = month; //new result. not saved, if there is an exception
while (daysNum > 0)
{
int daysToNextMonth = m_daysInMonth[n_month] - n_days + 1; //days before needs to change motn index
if (daysToNextMonth < daysNum) // change month
{
daysNum -= daysToNextMonth;
n_month++;
if (n_month > 12)
{
int daysLeft = m_daysInMonth[month] - days ;
n_month = month + 1;
while (n_month <= 12)
{
daysLeft += m_daysInMonth[n_month];
n_month++;
}
throw daysLeft;
}
n_days = 1; // start of the month
}
else // set day in the month
{
n_days += daysNum;
daysNum = 0;
}
}
days = n_days;
month = n_month;
}
};
Let's say we're developing an API for other programmers. Our API has a Date object for them to use, and we want to limit what values the month, day, and year can be to valid values, such as 1-12 for the month, 1-31 for the day, and 1900-2014 for the year. So to do this, we create separate Month, Day, and Year objects, all of which are passed to Date's constructor, which we call like so:
Date date(Month::Jan(), Day(1), Year(1980));
In order to ensure that Month can only be 1-12, we can create separate functions for each month, each of which returns a month object corresponding to that month, and to ensure that no one can create a month with the wrong value, we make Month's constructor private:
class Month {
public:
static Month Jan () { return Month(1);}
static Month Feb () { return Month(2);}
static Month Mar () { return Month(3);}
static Month Apr () { return Month(4);}
static Month May () { return Month(5);}
static Month Jun () { return Month(6);}
static Month Jul () { return Month(7);}
static Month Aug () { return Month(8);}
static Month Sep () { return Month(9);}
static Month Oct () { return Month(10);}
static Month Nov () { return Month(11);}
static Month Dec () { return Month(12);}
private:
Month (int n) : monthNum (n) {}
int monthNum;
};
However, for Day and Year, we can't have function names that only contain numbers like Year::1997() and we want this format to be intuitive to client developers, so syntaxes like Year::year1997() are out. Plus, we don't want to manually code a function for every possible year. Let's say years go back significantly far enough that this would be a problem, like back to 1900, for instance. So we'll stick with the Day(1) or Year(1997) format.
Given this, what's a good way to ensure that the constructed Day and Year can only return the range of values we want? One way is to throw an exception if invalid values are entered:
class Day {
public:
Day (int d) : dayNum(d) {
if(d <= 0 || d >= 31) {
throw "Invalid day";
}
}
private:
int dayNum;
};
But this generates an error during runtime, not during compile time, and we're building this for developers to use, so we want them to know as soon as possible when they've done something wrong, such as putting an invalid day or year (e.g. day 32 or year 3000). What's an effective way to ensure clients can only create Day or Year objects with valid values, without waiting until program execution to notify them?
Template may be an option. Check out this
I'm writing a program, in which I have some competitors, which are defined by structure. I also have a date structure.
struct date{ int d; int m; int y;};
I must sort competitor by their age, and I have no idea how to get age of competitors, to compare it.
I also tried this:
void age(tekmovalec comp){
#define _CRT_SECURE_NO_WARNINGS
time_t theTime = time(NULL);
struct tm *aTime = localtime(&theTime);
int day = aTime->tm_mday;
int month = aTime->tm_mon + 1; // Month is 0 - 11, add 1 to get a jan-dec 1-12 concept
int year = aTime->tm_year + 1900;
int age1, age2;
if(comp.rojDat.m > month){
age1=year-comp.rojDat.y-1;
age2=(12-month) + comp.rojDat.m;
}else{
age1=year-comp.rojDat.y;
age2=12-comp.rojDat.m;
}
int age3 = age1*12 + age2;
comp.age=age3;
}
But it returns error that localtime is unsafe.
As you want to sort by date, you may want to take a look at std::sort. For comparison, you need to write a function comp that compares 2 competitors (you need just to compare their ages, using basic comparations between days, months and years).
bool comp(competitor a, competitor b){
if(a.age.y < b.age.y)
return true;
else if(a.age.y == b.age.y && a.age.m < b.age.m)
return true;
else if(a.age.y == b.age.y && a.age.m == b.age.m && a.age.d < b.age.d)
return true;
else
return false;
}
Note that this is not the best implementation (actually it is pretty messy), but it's purpose is to give you a hint, not to be used as it is.
Another way to achive this is to overload comparison operators for competitors.
There is no need for localtime. You do not need age; what you need is a way to compare age. To determine which of us is older, we do not need to know what year this is, all we need to know is which of us was born earlier.
Write a function that compares two birthdates:
bool operator<(const date &A, const date &B)
{
...
}
Then use that to build a function that compares two competitors, then use that to build a function that sorts competitors.
instead of localtime() which can cause issues (not thread safe), you can use localtime_r() which should not have warnings :
struct tm *localtime_r(const time_t *restrict timer, struct tm *restrict result);
struct tm mytime; // use this instead of aTime
localtime_r(&theTime, &myTime)
int day = myTime.tm_mday;
int month = myTime.tm_mon + 1; // Month is 0 - 11, add 1 to get a jan-dec 1-12 concept
int year = myTime.tm_year + 1900;
This might also be localtime_s()
I presume you are using Visual studio. _CRT_SECURE_NO_WARNINGS needs to be a preprocessor definition (i.e. Seen before any #includes or code)
Right click on the project, get the 'Properties' menu and find the C/C++ preprocessor definitions and put it thre.
To actually compare times, it might be easier if you use mktime after transforming your dat struct into a tm, but you'll have trouble if anyone was born before 1970.
See here
For some reason, when I use the destructor for my Update class, a debug assertion fail message displays...
here is my Update class with some code omitted for brevity. Placed in a header file:
using namespace std;
class Update
{
private:
int day, month, year;
static const int FIELD_SIZE = 3, DEFAULT_DAY = 12, DEFAULT_MONTH = 12,
DEFAULT_YEAR = 1999, DAYS_IN_MONTH = 30, MONTHS_IN_YEAR = 12, DAYS_IN_YEAR = 365;
int * date;
public:
static int dateUpdate;
Update(int D, int M, int Y)
{
day = D;
if (day < 1 || day > DAYS_IN_MONTH)
day = DEFAULT_DAY;
month = M;
if (month < 1 || month > MONTHS_IN_YEAR)
month = DEFAULT_MONTH;
year = Y;
if (year < 1)
year = DEFAULT_YEAR;
date = new int [FIELD_SIZE];
date[0] = day, date[1] = month, date[2] = year;
dateUpdate++;
}
~Update()
{
delete [] date;
dateUpdate--;
}
};
and here is my tester class in a cpp file:
#include <iostream>
#include "Update.h"
int Update::dateUpdate = 0;
int main()
{
Update u1(29, 12, 2000);
u1.Update::~Update();
return 0;
}
I've read through other questions involving debug assertion failures but something tells me a debug assertion failure can occur in various ways. As a result, I have little clue as to why the error message is displaying for my code... Is there something wrong with my destructor as I suspect at the moment? Thank you so much for your help in advance!
The problem is because you are calling destructor explicitly:
u1.Update::~Update();
this way it is called twice causing undefined behaviour, I suppose delete [] date; is called twice, the second time on alreade freed memory.
Another problem in your code is that you are using bare pointer for you array:
int * date;
this is actually quite low level programming style in C++ and can cause lots of problems. You should implement class copy constructor and assignment operator (*) that will allocate new date array when your Update class will be copied, otherwise you will have again problems with multiple date pointer deletions.
The best way is to use vector like
std::vector<int> date;
(*) I think good link where rule of three (or since C++11 rule of five) that applies here is explained: Rule-of-Three becomes Rule-of-Five with C++11?
You should change this line:
date[0] = day, date[1] = month, date[2] = year;
To:
date[0] = day;
date[1] = month;
date[2] = year;
You are using the comma operator, which returns the result of the last expression. This is not the same as how the comma operates in an initialization.
Also, in your main function, you do not need to explicitly call the destructor.
Your date method can't handle January 31 nor December 31.
You can access the parameters of the function directly instead of making a copy in the function. For example: day = D; is not needed; access the parameter directly: if ((D < 1) ....
If you used unsigned integers you would not need to check for negative numbers. I've never experienced a negative day, month or year in my life.
Since this is C++ and not Java or C#, you don't need to dynamically allocate variables. So rather than using int * date you could use int date[3].
I am having troubles understanding this issue. The code is really basic but it behaves rather unexpectedly. The code is the simplified version of a routine to extract and save to a separate file the data for the day 15 of each month out of a daily database. Where is the problem ? The first cout prints the number of any day the outer if is entered. Then there are some conditional lines to select the right day ( not really important in this example ) and then there is the block, the inner if, that should print the data for the day 15 to the new file. Now, as you can see, while the outer loop ( attention ! ) is entered only on the 10th ( and this is already wrong - it should have written all the numbers from 11 to 15 ) but then it also prints that the file is written on the 15 ! Where is the problem ? The OUTER IF was entered only on the 10th, how can be the INNER IF be execute on the 15th ????
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string newdata="mamma";
string risultato="-";
string PriorLine="-";
int PriorDay=0;
int lastmonth=0;
// Loops through all the months
for (int mese=1; mese <=12; mese++)
{
//Loops through all the days in the month
for(int day=1; day<=30; day++)
{
// at the month's beginning these 2 strings are set ="-"
if (mese != lastmonth)
{
risultato="-";
PriorLine="-";
}
// if we are between the 10th and the 20th and the result is still to be found
if (day>=10 && day<=20 && risultato=="-")
{
cout << day << endl; // LISTS ALL THE DAYS THIS LOOP IS ENTERED
if (day=15) // if it is exactly day 15 print that day's result
risultato=newdata;
// if that month in the data there is no day 15 and
// this is the second pass, choose the closest !
if (day>15 && PriorLine !="-")
{
if (abs(day-15)<=abs(15-PriorDay))
risultato=newdata;
else
risultato=PriorLine;
}
PriorLine=newdata;
PriorDay=day;
if (risultato != "-")
{
// writes the result ( risultato ) in a file
cout << "file written on the " << day << endl;
}
}
lastmonth=mese;
}
}
system("pause");
return 0;
}
if (day=15) assigns 15 to day and returns true. You need if (day==15)
When I simply compiled your code with g++ -Wall I got a warning:
error: suggest parentheses around assignment used as truth value
On this line:
if (day=15) // if it is exactly day 15 print that day's result
I'm willing to be the compiler has told you what your problem is. I suggest you enable all warnings in your build system.