Get function that "gets" other get functions - c++

So my challenge is: create a function that receives all of the parameters from the other get functions, like:
int get_day() const {return day;}
int get_month() const {return month;}
int get_year() const {return year;}
I want get_date() that receives all of the above gets. How can I do that? For example:
int get_date() const {
get_day();
get_month();
get_year();
}

You may pack the date like this:
int get_date() const {
return get_day() + 100 * get_month() + 10000 * get_year();
}
Note, that this is just integer, that looks like date. If you print today's date, it will be the number 20190423, which is just the number 20,190,423.

As I mentioned in the comments, it makes no sense to return a single int when you need your function to return 3 ints.
Just return an array like this:
#include <iostream>
#include <array>
struct Cal
{
typedef std::array<int,3> Date;
int day = 13;
int month = 7;
int year = 2019;
int getDay() const
{
return day;
}
int getMonth() const
{
return month;
}
int getYear() const
{
return year;
}
Date getDate() const
{
return {{getDay(),getMonth(),getYear()}};
}
};
int main()
{
Cal c;
for (auto &&i : c.getDate())
std::cout<< i <<" ";
std::cout<<std::endl;
}
The code outputs:
13 7 2019
Also, it's best if you simply returned the actual members instead of calling the getter functions. Besides the getDate() function is also a member of the class.
Date getDate() const
{
return {{day,month,year}};
}
Online code example: https://rextester.com/WPXX24681

you can use tm struct as in here: std::tm
std::time_t t = std::time(0);
std::tm* now = std::localtime(&t);
std::cout << (now->tm_year + 1900) << (now->tm_mon + 1) << (now->tm_mday);
don't reinvent the wheel

Related

How can I change the parameters of a default constructor?

I have a class called Date that controls the date.
I have a constructor Date(). If this constructor is uninitialized, a default date will be put in its place by a private, static data member called default_.
I have initialized default_ in Date.cpp as follows:
Date Date::default_{1, Month::January, 1900};
Where the first argument is an int for the day, second is an enum class called Month for the month, and third is an int for the year.
When I run this program, I can print the date and it shows the correct default date that has been set by default_.
Question:
I want to be able to change the default date with a function:
setDefaultDate(int day, Month month, int year)
How can I do this? I have tried to implement setDefaultDate() as follows but it is not working:
void Date::setDefaultDate(int day, Month month, int year)
{
default_ = {day,month,year};
}
Code:
Date.h:
#ifndef DATE_H
#define DATE_H
// date.h
// class Date declaration
#include <cassert>
#include <iostream>
using namespace std;
enum class Month
{
January = 1,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December
};
class Date
{
public:
// return the day of the month
int day () const;
// return the month of the year
Month month () const;
// return the year
int year () const;
Date();
static void setDefaultDate(int day, Month month, int year);
private:
int day_;
Month month_;
int year_;
static Date default_;
};
// standalone function for printing the date
void printDate(const Date& date);
#endif
Date.cpp:
// date.cpp
// Implementation of the Date class
#include "date.h"
int Date::day() const
{
return day_;
}
Month Date::month() const
{
return month_;
}
int Date::year() const
{
return year_;
}
// Note, this standalone function is not part of the Date class
void printDate(const Date& date)
{
cout << date.day() << "/"
// cast to an integer to allow the month to be sent to the stream
<< static_cast<int>(date.month()) << "/"
<< date.year()
<< endl;
}
Date Date::default_{1, Month::January, 1900};
void Date::setDefaultDate(int day, Month month, int year)
{
default_ = {day,month,year};
}
Date::Date()
{
day_ = default_.day();
month_ = default_.month();
year_ = default_.year();
}
Example
int main()
{
auto date_1 = Date{};
date_1.setDefaultDate(29, Month::September, 2020);
printDate(date_1);
}
Expected output:
29/9/2020
Actual Output:
1/1/1900
It compiles, but the setDefaultDate() function is not working, and the default date is being outputted that was declared in default_.
Let's step through your main line by line:
auto date_1 = Date{};
What will this do? It will call Date::Date, which will read all of the values from default_ into date_1. At this point default_ is 1/1/1900 and date_1 now is the same. Then
date_1.setDefaultDate(29, Month::September, 2020);
will change default_ and default_ only. I'm not sure why you expect date_1 to change here, maybe because you've called it like a non-static member function? You probably meant to change the default date before reading from it. You can do it like so:
int main()
{
// call it like static function
Date::setDefaultDate(29, Month::September, 2020);
// Only then read from it.
auto date_1 = Date{};
// prints 29/9/2020
printDate(date_1);
}
Your setDefaultDate() method sets only the value of default_, which main() has already made a copy of when calling the Date() constructor for the date_1 object. Changing the value of default_ afterwards has no effect whatsoever on the value of date_1. When you print date_1, you output the value it was initialized with. Changing the value of default_ will only have an effect on subsequent Date objects that you create afterwards.
If you want to change the value of date_1, you need to either:
call setDefaultDate() before calling Date():
int main()
{
Date::setDefaultDate(29, Month::September, 2020);
Date date_1;
printDate(date_1); // 29/9/2020
}
add non-static methods to mutate the values of a Date object. You should also add a non-default constructor that can take a user-specified date as input, eg:
class Date
{
public:
Date();
Date(int initialDay, Month initialMonth, int initialYear);
...
void setDay (int newValue);
void setMonth (Month newValue);
void setYear (int newValue);
...
};
Date::Date() :
Date(default_.day_, default_.month_, default_.year_)
{
}
Date::Date(int initialDay, Month initialMonth, int initialYear) :
day_(initialDay),
month_(initialMonth),
year_(initialYear)
{
}
void Date::setDay (int newValue)
{
day_ = newValue;
}
void Date::setMonth (Month newValue)
{
month_ = newValue;
}
void Date::setYear (int newValue)
{
year_ = newValue;
}
...
int main()
{
Date date_1;
printDate(date_1); // 1/1/1900
date_1.setDay(29);
date_1.setMonth(Month::September);
date_1.setYear(2020);
printDate(date_1); // 29/9/2020
date_1 = Date(9, Month::September, 2020);
printDate(date_1); // 9/9/2020
Date date_2(31, Month::December, 2020);
printDate(date_2); // 31/12/2020
Date::setDefaultDate(1, Month::April, 2020);
Date date_3;
printDate(date_3); // 1/4/2020
}
I will show you a modified version of your code that should do what you need to, if I understood it correctly. I changed your code a bit, in order to use a single file
java is not C++, C++ is not java. And static things in C++ goes not the java way. Maybe you are used to that.
One thing is in C++ you can set up the defaults running code just outside of main() and outside the class as
...
}; // class Date{}
int Date::default_day = 1;
int Date::default_month = 1;
int Date::default_year = 1900;
void printDate(const Date& date);
void setDefaultDate(int, int, int);
int main(void)
{
...
And so you have the first set of defaults loaded.
And if you do it inside main() it compiles but the linker will
complain about all 3 of them as unresolved.
for setDefaultDate() you can just declare it as Date's friend
friend void setDefaultDate(int, int, int);
a convenient and common alternative to PrintDate() is to declare another friend to Date, as
friend ostream& operator<<(ostream&, Date&);
An example using your code
Program shows
just a date at start (should use defaults 1900,1,1)
printDate()
d: 1 m: 1 y: 1900
Now sets default to 1901/3/2
printDate()
d: 2 m: 3 y: 1901
Now declared new Date instance as d3(2019,8,7)
printDate()
d: 7 m: 8 y: 2019
Now print all 3 dates using "<<" operator, redefined for Date class
printDate using insertion operator '<<'
year is 1900 month is 1 year is 1900
printDate using insertion operator '<<'
year is 1901 month is 3 year is 1901
printDate using insertion operator '<<'
year is 2019 month is 8 year is 2019
main() is
int main(void)
{
cout << "\njust a date at start (should use defaults 1900,1,1)\n";
Date d1;
printDate(d1);
cout << "\nNow sets default to 1901/3/2\n";
setDefaultDate(2, 3, 1901);
Date d2;
printDate(d2);
cout << "\nNow declared new Date instance as d3(2019,8,7)\n";
Date d3(2019, 8, 7);
printDate(d3);
cout << "\nNow print all 3 dates using \"<<\" operator, redefined for Date class\n";
cout << d1 << d2;
cout << d3;
return 0;
}
Code uses printDate() and also the overloaded << as an alternative to printDate(). I left two cout for the 3 Date just to show that you can chain the printing as with any other cout call.
The program sets the defaults before and inside main()
I added a 2nd constructor that accepts day, month and year as arguments
the complete example
#include <iostream>
using namespace std;
class Date
{
private:
int year_;
int month_;
int day_;
public:
int year() const { return year_; };
int month() const { return month_; };
int day() const { return day_; };
// default as Date d;
Date() :
year_(default_year), month_(default_month), day_(default_day) {};
// as Date d(2020,9,8)
Date(int y, int m, int d) :
year_(y), month_(m), day_(d){};
friend void setDefaultDate(int, int, int);
friend ostream& operator<<(ostream&, Date&);
private:
static int default_year;
static int default_month;
static int default_day;
}; // class Date{}
int Date::default_day = 1;
int Date::default_month = 1;
int Date::default_year = 1900;
void printDate(const Date& date);
void setDefaultDate(int, int, int);
int main(void)
{
cout << "\njust a date at start (should use defaults 1900,1,1)\n";
Date d1;
printDate(d1);
cout << "\nNow sets default to 1901/3/2\n";
setDefaultDate(2, 3, 1901);
Date d2;
printDate(d2);
cout << "\nNow declared new Date instance as d3(2019,8,7)\n";
Date d3(2019, 8, 7);
printDate(d3);
cout << "\nNow print all 3 dates using \"<<\" operator, redefined for Date class\n";
cout << d1 << d2;
cout << d3;
return 0;
}
void printDate(const Date& date)
{
cout << "\nprintDate()\n" <<
" d: " << date.day() <<
" m: " << date.month() <<
" y: " << date.year()
<< endl;
};
void setDefaultDate(int day, int month, int year)
{
Date::default_day = day;
Date::default_month = month;
Date::default_year = year;
};
ostream& operator<<(ostream& out, Date& date)
{
cout << "\nprintDate using insertion operator '<<'\n" <<
"\tyear is " << date.year_ <<
" month is " << date.month_ <<
" year is " << date.year_ <<
endl;
return out;
};
No religion here. I compiled it just under MSVC 19.27

How to use array with pointer?

I am new to programming and an trying to create an array with a series of records in and then have the programme accept input and finally print out the contents of the list.
I am having trouble recording the values of some of the variables in my addRecord() function as the output of the code below is the following:
constructor called
-1:-1 Eat lunch
-1:-1 Watch TV
destructor called
Why am I missing the call to L1.addRecord(5, 30, "Make dinner"); completely and why aren't the times coming through (they are coming through as -1 which is set in the constructor)?
Thank you
#include <iostream>
#include <string>
using namespace std;
class Record {
private:
int hour;
int minute;
string todo;
public:
Record()
{
hour = -1;
minute = -1;
todo = "N/A";
}
void setData(int hour, int minute, const char* td);
void setData(Record& e);
void printRecord();
};
class List
{
private:
Record* recordArr;
int maxRecords;
int actualRecordCount;
public:
List(int maxRecords);
List(List& s) {
actualRecordCount = s.actualRecordCount;
maxRecords = s.maxRecords;
recordArr = new Record[maxRecords];
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].setData(s.recordArr[i]);
}
std::cout << "copy constructor called." << std::endl;
}
~List();
bool addRecord(int hour, int minute, const char* todo);
void printList();
};
///////////////////////////
void Record::setData(int hour, int minute, const char* td)
{
hour = hour;
minute = minute;
todo = td;
}
void Record::setData(Record& e)
{
hour = e.hour;
minute = e.minute;
todo = e.todo;
}
void Record::printRecord()
{
std::cout << hour << ":" << minute << " " << todo << std::endl;
}
List::List(int maxRecords)
: maxRecords(maxRecords)
{
actualRecordCount = 0;
recordArr = new Record[maxRecords];
std::cout << "constructor called" << std::endl;
}
List::~List()
{
std::cout << "\ndestructor called";
delete[] recordArr;
}
bool List::addRecord(int hour, int minute, const char* todo)
{
Record newRecord; // create new Record
newRecord.setData(hour, minute, todo); //assign values
if (actualRecordCount >= maxRecords) // array full
{
return false;
}
else
{
recordArr[actualRecordCount] = newRecord; // put new Record into the array of Entry
actualRecordCount++; // increment Entry count
return true;
}
}
void List::printList()
{
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].printRecord();
cout << endl;
i++;
}
}
int main() {
List L1(20);
L1.addRecord(2, 30, "Eat lunch");
L1.addRecord(5, 30, "Make dinner");
L1.addRecord(7, 30, "Watch TV");
L1.printList();
}
void Record::setData(int hour, int minute, const char* td)
{
hour = hour;
"hour" is the name of a parameter to this setData() method. hour=hour;, therefore, sets this parameter to itself. This accomplishes absolutely nothing, whatsoever. Same for other two assignments that follow.
Your obvious intent here is to initialize the class that happens to have members with the same name. When different things have the same name in C++ there's a complicated set of rules that choose which "thing" the name represents. These rules are the same on the left and the right side of the = operator, so both of these hours end up referring to the same object: the parameter to this class method.
You can simply rename the parameters to the method:
void Record::setData(int hourArg, int minuteArg, const char* tdArg)
{
hour = hourArg;
and so on. Or, if you wish to keep the parameter names the same, make things more explicit:
this->hour=hour;
The other error is here
void List::printList()
{
for (int i = 0; i < actualRecordCount; i++)
{
recordArr[i].printRecord();
cout << endl;
i++;
}
}
You have i++ twice.
One problem is that your Record::setData function with three arguments doesn't actually set the hour and minute fields of the class object! This is caused by your use of arguments with the same name as the class members, which (IMHO) is bad coding style. So, in the following code, your first two assignments just replace the argument values with themselves:
void Record::setData(int hour, int minute, const char* td)
{
hour = hour; // This and the following line are self-assignments to the arguments
minute = minute; // given and, as such, are effectively doing nothing!
todo = td; // This, however, is OK, because there is no ambiguity.
}
To fix this, either add an explicit this-> reference to the targets:
void Record::setData(int hour, int minute, const char* td)
{
this->hour = hour;
this->minute = minute;
todo = td;
}
Or (much better, in my opinion) give the first two arguments non-ambiguous names:
void Record::setData(int in_hour, int in_minute, const char* td)
{
hour = in_hour;
minute = in_minute;
todo = td;
}

How to push_back a class object into a std::vector?

I have some trouble figuring out a few things. Basically I have 2 classes, and whenever I create the objects, it works completely fine. However when I try to push_back to a vector in main() function, it return 0 0 0 (B default values), and if I try to make a void function, which would do this, it gives back segmentation fault. Any ideas?
class Date
{
public:
Date(int day=0, int month=0, int year=0) : _day(day), _month(month),_year(year) {}
int get_day() { return _day; }
int get_month() { return _month; }
int get_year() { return _year; }
void writestuff() { std::cout << _day << "/" << _month << "/" << _year<< std::endl; }
~Date(){}
private:
int _day;
int _month;
int _year;
};
class Adatok
{
public:
Adatok(std::string name, std::string path, Date date ): _name(name), _path(path), _date(date) {}
void writestuff()
{
std::cout<<_name<<" "<<_path<<" ";
_date.writestuff();
std::cout<<std::endl;
}
Adatok(const Adatok& other){}
Adatok operator= (const Adatok& other){}
~Adatok(){}
private:
std::string _name;
std::string _path;
Date _date;
};
void database(std::string& temp, std::vector<Adatok> my_vec); // this would be the segmentation fault code, it's not implemented anymore
int main(int argc, char **argv)
{
std::vector<Adatok> my_vec;
std::string temp;
boost::filesystem::ifstream input_file("input");
while (getline(input_file, temp))
{
//---------------------------------don't mind theese------------------------------------------------------------------
temp += ',';
std::string name = temp.substr(temp.find_first_of('"'),temp.find_first_of(','));
temp.erase(0, name.length() + 1);
std::string path = temp.substr(temp.find_first_of('"'),temp.find_first_of(','));
temp.erase(0, path.length() + 1);
std::string numbers(temp.substr(temp.find_first_of('"') + 1,temp.find_first_of('-')));
int year, month, day;
year = std::atoi(numbers.c_str());
temp.erase(0, temp.find_first_of('-') + 1);
numbers = temp.substr(0, temp.find_first_of('-'));
month = std::atoi(numbers.c_str());
temp.erase(0, temp.find_first_of('-') + 1);
numbers = temp.substr(0, temp.find_first_of(' '));
day = std::atoi(numbers.c_str());
//Date obj(day, month, year);
//Adatok elem(name, path, obj);
//---------------------------------------don't mind theese-----------------------------------------------------------------
my_vec.push_back(Adatok(name,path,Date(day,month,year))); //probably fails
}
for(std::vector<Adatok>::iterator it{my_vec.begin()};it !=my_vec.end();it++)
it -> writestuff();
return 0;
}
"however when i try to push_back to a vector in MAIN function, it
return 0 0 0 (B default values)"
This is because of not initializing the member variables of B class. This should be done when you push_back the a new A object to the std::vector like follows:
vecA.push_back(A("name", "path", B(15, 04, 2018)));
If your doubt is how to to use push_back is, above will certainly clarified it.
Update: I have set the copy constructor and copy assignment operator to default and it worked. Live action: https://www.ideone.com/TlmAm2
#include <iostream>
#include <string>
#include <vector>
class Date
{
public:
Date(int day = 0, int month = 0, int year = 0)
: _day(day), _month(month),_year(year) {}
~Date(){}
int get_day() { return _day; }
int get_month() { return _month; }
int get_year() { return _year; }
void writestuff()
{
std::cout << _day << "/" << _month << "/" << _year<< std::endl;
}
private:
int _day;
int _month;
int _year;
};
class Adatok
{
public:
Adatok(std::string name, std::string path, Date date )
: _name(name), _path(path), _date(date) {}
~Adatok(){}
void writestuff()
{
std::cout<<_name<<" "<<_path<<" ";
_date.writestuff();
std::cout<<std::endl;
}
//change in copy constructor and copy assignment operator
Adatok(const Adatok& other) = default;
Adatok& operator= (const Adatok& other) = default;
private:
std::string _name;
std::string _path;
Date _date;
};
void database(std::string temp, std::vector<Adatok> my_vec)
{
for(auto& it: my_vec)
it.writestuff();
}
int main(int argc, char **argv)
{
std::vector<Adatok> my_vec;
int year = 2018, month = 04, day = 15;
std::string name = "name1", path = "path1";
my_vec.push_back(Adatok(name,path,Date(day,month,year)));
database("something", my_vec);
return 0;
}

How can I make a class duration to store time length?

I am trying to write a class with 3 attribute and some constructors and following methods: set (h, m, s), Double getHousrs () operator +
correctTime(). To change e.g 1:76:84 to 2:13:13
Current code
#include <iostream>
using namespace std;
class duration {
public:
duration(int h, int m, int s)
:hour (h), minutes (m), seconds (s);
{}
void printDate()
{
cout << hour<< ":" << minutes << ":" << seconds << endl;
}
double getHours() {
return hours;
}
double getSeconds() {
return seconds;
}
private:
int hour;
int minutes;
int seconds;
duration operator+(duration &obj)
{ }
};
int main()
{
duration obj;
return 0;
}
The solution to your problem would be to add the values together which can be most efficiently done like this I also fixed all the other errors you had in your class:
#include <iostream>
using namespace std;
class duration {
public:
duration(int h, int m, int s)
:hour (h), minute (m), second (s)
{}
void printDate()
{
cout << hour<< ":" << minute << ":" << second << endl;
}
double getHours() {
return hour;
}
double getSeconds() {
return second;
}
duration operator + (const duration& other)
{
duration temp(0, 0, 0);
temp.second = (other.second+second)%60;
temp.minute = ((other.second + second)/60 + other.minute + minute)%60;
temp.hour = ((other.minute+minute)/60 + other.hour + hour)%60;
return temp;
}
private:
int hour;
int minute;
int second;
};
int main()
{
duration obj(3, 5, 10);
duration obj2(4, 55, 40);
duration temp = obj + obj2;
temp.printDate();
return 0;
}

Access Violation(Segmentation Fault )

I have two classes (appointment, schedule), and a driver (main).
main.cpp:
#include <iostream>
#include "schedule.h"
#include "appointment.h"
using namespace std;
int main()
{
schedule mySch2("hello");
appointment myAppt(100002,"appointment",10,1,2013);
myAppt.printS(cout,2);
mySch2.addtoSchedule(myAppt);
system("PAUSE");
return EXIT_SUCCESS;
}
schedule.h
#ifndef SCHEDULE_H
#define SCHEDULE_H
#include<iostream>
#include "appointment.h"
using namespace::std;
const int SCH_ENTRIES = 10;
class schedule
{
public:
schedule(void);
schedule(const char *p);
bool addtoSchedule(const appointment &);
private:
char title[40];
int count;
appointment appointmentArray[SCH_ENTRIES];
};
#endif
schedule.cpp
#include "schedule.h"
#include "appointment.h"
#include <iostream>
using namespace::std;
schedule::schedule(void)
{
}
schedule::schedule(const char *p)
{
strcpy(title, p);
count = 0;
cout << title << endl;
cout << count << endl;
cout << "----" << endl;
}
bool schedule::addtoSchedule(const appointment & myAppt)
{
cout << appointmentArray[0].getDay();
return false;
}
appointment.h (I did not write this, this was provided) - not super important for this question
#ifndef APPOINTMENT_H
#define APPOINTMENT_H
#include <fstream>
#include <cstring>
using std::ostream;
// The Designer decides upon the following data and actions (i.e. Functions)
// and places the class in the file appointment.h
class appointment
{
public:
appointment(void); // default constructor
appointment(long, const char [],int d, int m, int y); // 5 argument constructor
appointment(const appointment &); // copy constructor
void keyBoardInput(void); // Assume no blanks in the desc
long getSource(void) const; // return source
void setSource(long); // change source
void setMonth(int);
void setDay(int);
void setYear(int);
int getMonth(void) const;
int getDay(void) const;
int getYear(void) const;
const char *getDescription(void) const; // return the address of the description
void changeDescription(const char *) ; // change an existing description
void copyTo(appointment &) const; // copy invoking instance to parameter
void incrementDate (void); // advance the date by ONE day
// You can assume 30 days in each month
void printS(ostream &, int dateFormat) const; // print all fields
// dateFormat == 1 month/day/year
// dateFormat == 2 day/month/year
~appointment(); // destructor - indicate the address
// of the variable that is leaving
private:
void setDescription(const char *); // used to allocated memory
// data
long source; // id of the person scheduling the appointment
char * desc; // description of the appointment - Dynamic Data
int day; // day, month, and year when the appointment
int month; // will happen
int year;
};
#endif
appointment.cpp (I did not write this, this was provided) - not super important for this question
#include "appointment.h"
#include <iostream>
using std::cin;
using std::cout;
appointment::appointment()
{
day = 0;
cout << "default appt\n";
}
appointment::appointment(long lSource, const char cDescription[], int d, int m, int y)
{
source = lSource;
day = d;
month = m;
year = y;
setDescription(cDescription);
}
appointment::appointment(const appointment & aToCopy)
{
source = aToCopy.getSource();
day = aToCopy.getDay();
month = aToCopy.getMonth();
year = aToCopy.getYear();
setDescription(aToCopy.getDescription());
}
void appointment::setDescription(const char * cSource)
{
if (desc != NULL) free (desc);
if (cSource == NULL)
return;
desc = (char *)malloc (strlen (cSource) + 1);
strcpy(desc, cSource);
}
long appointment::getSource(void) const
{
return source;
}
void appointment::setSource(long lSource)
{
source = lSource;
}
void appointment::setMonth(int iMonth)
{
month = iMonth;
}
void appointment::setDay(int iDay)
{
day = iDay;
}
void appointment::setYear(int iYear)
{
year = iYear;
}
int appointment::getMonth(void) const
{
return month;
}
int appointment::getDay(void) const
{
return day;
}
int appointment::getYear(void) const
{
return year;
}
//return the address of the description
const char * appointment::getDescription(void) const
{
return desc;
}
//change an existing description
void appointment::changeDescription(const char * cDescription)
{
setDescription(cDescription);
}
void appointment::copyTo(appointment &p) const
{
p.source = source;
p.day = day;
p.month = month;
p.year = year;
p.setDescription(desc);
}
void appointment::incrementDate(void)
{
int days;
switch (month)
{
case 1: // Jan: 31 Days
case 3: // Mar: 31 Days
case 5: // May: 31 Days
case 7: // Jul: 31 Days
case 10: // Oct: 31 Days
case 12: // Dec: 31 Days
days = 31;
break;
case 4: // Apr: 30
case 6: // Jun: 30
case 8: // Aug: 30
case 9: // Sep: 30
case 11: // Nov: 30
days = 30;
break;
case 2: // Feb: 28/29 Days (Depends on year modulus 4 a modulus 100).
days = !(year % 4) || !(year % 100) ? 29 : 28;
break;
}
day++;
if (day > days)
{
month++;
day = 1;
if (month > 12)
{
month = 1;
year++;
}
}
}
void appointment::printS(ostream &out, int dateFormat) const
{
if (dateFormat == 1)
{
out << month << "/" << day << "/" << year << "\n";
}
else if (dateFormat == 2)
{
out << day << "/" << month << "/" << year << "\n";
}
else
out << "Unsupported dateFormat parameter specified (should be 1 or 2).";
}
appointment::~appointment()
{
if (desc != NULL)
{
free (desc);
desc = NULL;
}
}
void appointment::keyBoardInput()
{
char temp[1024];
cout << "Please type the description: ";
cin.getline (temp, sizeof(temp) - 1, '\n');
cout << std::endl;
setDescription(temp);
}
My error occurs when the main driver calls mySch2.addtoSchedule(myAppt);
If I uncomment out the line inside of schedule appointmentArray[0].getDay() then everything runs and works fine with no segmentation error. As soon as that line gets uncommented, it throws the error during runtime (after a crash and I go into the debugger and step through the program).
You never initialize desc to nullptr for class appointment before invoking setDescription. This happens in both constructors. Learn to use an initializer list:
appointment::appointment()
: source(), desc(), day(), month(), year()
{
cout << "default appt\n";
}
appointment::appointment(long lSource, const char cDescription[], int d, int m, int y)
: source(lSource), desc(), day(d), month(m), year(y)
{
setDescription(cDescription);
}
appointment::appointment(const appointment & aToCopy)
: source(aToCopy.getSource())
, desc()
, day(aToCopy.getDay())
, month(aToCopy.getMonth())
, year(aToCopy.getYear())
{
setDescription(aToCopy.getDescription());
}
Why did it fault?
Without initialization the value in desc is indeterminate and therefore undefined behavior to dereference, and certainly so to pass to free.
void appointment::setDescription(const char * cSource)
{
if (desc != NULL) free (desc); // desc contains non-null garbage.
if (cSource == NULL)
return;
desc = (char *)malloc (strlen (cSource) + 1);
strcpy(desc, cSource);
}
That said, I would strongly encourage using a std::string instead. It would make the copy-consructor for this class completely disappear, and the default constructor trivial.
Comments about using malloc() in a C++ program reserved, as that opinion is all-but beat to death already on this forum (and I agree with te prevailing opinion).