Get age out of date structure - c++

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

Related

What is the point in returning values?

I'm fairly new when it comes to C++ so bear with me. When learning about return values in functions, I was told that the proper way to write pure functions is to return a value every time. I attempted this in a small function that checks the user's age and returns whether or not they're an adult. The issue here, at least for me, is understanding the proper utilization of these return values. For example, in this code snippet here I'm returning whether or not they are an adult given their age in years.
main.h
#pragma once
#define LOG(x) std::cout << x
#define LOGCIN(x) std::cin >> x
bool check_age(int age) {
if (age >= 18)
return true;
else
return false;
}
main.cpp
#include <iostream>
#include "main.h"
bool check_age(int age);
int main() {
int age;
LOG("Enter your current age in years: ");
LOGCIN(age);
bool adult = check_age(age);
if (adult == true) {
LOG("You are an adult!");
} else {
LOG("You are not an adult!");
}
}
However, when I rewrote this code without using return values, I got this.
main.h
#pragma once
#define LOG(x) std::cout << x
#define LOGCIN(x) std::cin >> x
void check_age(int age) {
if (age >= 18)
LOG("You are an adult!");
else
LOG("You are not an adult!");
}
main.cpp
#include <iostream>
#include "main.h"
void check_age(int age);
int main() {
int age;
LOG("Enter your current age in years: ");
LOGCIN(age);
check_age(age);
}
As you can see, the latter code choices is simpler and more compact. If code requires more lines and takes longer to write with return values, then what's even the point in using them?
Often the purpose of a function is not just to log something to cout but instead make a decision based on some parameters, or return a value so it can be used flexibly. An example of this would be in binary search:
while(l <= r) {
int mid = (l+r)>>1;
if(check(/* parameters */)) {
//update answer
r = mid+1;
} else l = mid-1;
}
Of course, you could make your function edit a global variable and make decisions based off of that; but it will make the code more verbose:
while(l <= r) {
int mid = (l+r)>>1;
check(/* parameters */);
if(ok /* global variable*/) {
//update answer
r = mid+1;
} else l = mid-1;
}
As an additional example, it is a lot easier to write (and read):
round(a)+ceil(b)
than have these functions update global variables.
Imagine the function is provided by someone else.
In that case, we may not be able to know its implementation.
How does our program know whether the function succeeds or not?
Besides, sometimes we want to know some information from a function. I think that's why return values are used.
Returning a value from the function serves an important purpose - it allows you to separate the two concepts of "determine whether this person is an adult" and "print some stuff about this person".
You could imagine tons of scenarios where the program would need to know if someone was an adult without printing it to console - such as allowing them to buy alcohol, register for college, etc etc etc.
And you could also imagine that if you knew someone was an adult, there might be a ton of different ways you'd like to print that (imagine other languages, or rendering it on a webpage, or etc etc).
So by returning the value, you enable this separation of concepts which makes your code much more flexible in the future.
Maybe you don't need that for a toy example, but that's sorta beside the point when you're asking a broad design question like this.

Changing date for certain amount of days function

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;
}
};

C++: proper format to initialize derived and base along

I have made a date class that can hold the month, the day, and the year. But now I have a problem.
I've used this date class with inheritance to store for example the dateOfBirth for person(receptionist, passenger, and etc) (A hotel) by the Ctor of person(in fact using Ctor of date class in the initialization list of person), but now I don't know what is the format which I should use in main to initialize a person?! Is there anyway that I can do it directly in main at all? Sorry I'm beginner. Any help appreciated.
Here's some parts of my code:
class date {
int month = 1;
vector<int>month_days{ 31,31,31,31,31,31,30,30,30,30,30,29 };
int day = 1;
int year = 1300;
//---------------------member functions:
public:
date(int m = 1, int d = 1, int y = 1300) {
if (m>0 && m <= 31) month = m;
if (d>0 && d <= 31) day = d;
if (y>0 && y <= 3000) year = y;
}
//some other code...
};
class person:public date {
protected:
string m_name;
string m_familyName;
string m_idNumber;
//---------------------member functions:
public:
person(string name, string familyName, string idNumber, date dateOfBirth)
: m_name(name),m_familyName(familyName),m_idNumber(idNumber),date(dateOfBirth)
{
}
//some other code...
};
This is what I typed in main and I know that it can't do the job:
person a("Michael", "Deoran", "05174084", (4,17,1998));
I checked the stored date for object "a" and its date returns 1,1,1300, nevertheless, I don't know what can do the job too.
(By the way, the reason I defined a date, separate from person, is that I overloaded the operator- in it to calculate the stay time of passenger)
All you need to do is change parentheses to braces (that is for the code to compile, not to be also well-designed and not producing -Wreorder warnings):
person a("Michael", "Deoran", "05174084", {4, 17, 1998});
- list initialization.
The version with parentheses is equivalent to (comma operator):
person a("Michael", "Deoran", "05174084", 1998);
I would think twice before providing default values for the parameters. You probably don't need them.

Adding the year implementation in c++ using a class

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.

Debug assertion failed message

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].