How to push_back a class object into a std::vector? - c++

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

Related

logical exception output error for function setHeight and function setWeight [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 days ago.
Improve this question
When I input this:
Anne Niebuhr 2 15 1996 -104.9 5.7
y
Jesse Choi 12 4 1962 161.9 5.11
n
I get this logical error:
I want to print this output
In Person.cpp I use the try block on function setHeight and function setWeight, which then be thrown to PersonExceptions.cpp to return an input exception error. When I run the program it prints out the invalid statement and prints out the invalid input. How do I make the program to not print out |Anne|Niebuhr|Febraury 15, 1996| 5.7 feet| 0 lbs|?
main.cpp:
#include <iostream>
#include <vector>
#include "Date.h"
#include "Person.h"
#include "DateException.h"
#include "PersonExceptions.h"
int main() {
std::string firstName;
std::string lastName;
int birthMonth;
int birthDay;
int birthYear;
float height;
float weight;
char answer = 'y';
std::vector<CIST2362::Person> personDatabase; // vector of Person Objects
// input person objects
// You must catch exceptions properly
while (toupper(answer) == 'Y') {
std::cin >> firstName;
std::cin >> lastName;
std::cin >> birthMonth;
std::cin >> birthDay;
std::cin >> birthYear;
std::cin >> weight;
std::cin >> height;
// place person objects into vector
//
CIST2362::Person data(firstName,lastName,birthDay,birthMonth,birthYear,height,weight);
personDatabase.push_back(data);
std::cin >> answer;
}
// output the person objects
for(int i=0;i<personDatabase.size();i++)
{
CIST2362::Person data=personDatabase[i];
std::cout<<data.toString();
}
return 0;
}
Person.cpp:
#include <sstream>
#include <iomanip>
#include "Person.h"
#include "PersonExceptions.h"
namespace CIST2362 {
const std::string &Person::getFirstName() const {
// return firstName value
return firstName;
}
void Person::setFirstName(const std::string &firstName) {
// points to firstName
this->firstName = firstName;
}
const std::string &Person::getLastName() const {
// return lastName value
return lastName;
}
void Person::setLastName(const std::string &lastName) {
// points to firstName
this->lastName = lastName;
}
const Date &Person::getBirthdate() const {
//return birthdate value
return this->birthdate;
}
void Person::setBirthdate(const Date &birthdate) {
// points to firstName
this->birthdate=birthdate;
}
float Person::getHeight() const {
//return height value
return this->height;
}
void Person::setHeight(float height) {
// try if height are less than 0
try{
if(height<0){
// throws char
badHeight w;
throw w;
}
else{
this->height = height;
}
}
catch(std::exception& e){
std::cout<<e.what();
}
}
float Person::getWeight() const {
//return weight value
return this->weight;
}
void Person::setWeight(float weight) {
// try if weight are less than 0
try{
if(weight<0){
// throws char
badWeight w;
throw w;
}
else{
this->weight = weight;
}
}
// catch error
catch(std::exception& e){
std::cout<<e.what();
}
}
Person::Person(const std::string &firstName, const std::string &lastName, int birthday,
int birthmonth, int birthyear, float height, float weight) : firstName(firstName),
lastName(lastName), birthdate(birthday, birthmonth, birthyear) {
// returns the input objects
this->setFirstName(firstName);
this->setLastName(lastName);
this->setHeight(height);
this->setWeight(weight);
this->birthdate.setDay(birthday);
this->birthdate.setMonth(birthmonth);
this->birthdate.setYear(birthyear);
}
std::string Person::toString()const{
std::stringstream heightSS, weightSS;
heightSS << height;
weightSS << weight;
// formats the inputs
return "|"+firstName + "|" + lastName + "|" + birthdate.getDateLong() + "| " + heightSS.str() + " feet" + "| " + weightSS.str() + " lbs" + "|\n";
}
}
`
`#ifndef LESSON_5_PROGRAMMING_ASSIGNMENT_PERSON_H
#define LESSON_5_PROGRAMMING_ASSIGNMENT_PERSON_H
#include <string>
#include "Date.h"
namespace CIST2362 {
class Person {
private:
std::string firstName;
std::string lastName;
Date birthdate;
float height;
float weight;
public:
Person(const std::string &firstName, const std::string &lastName, int birthday, int birthmonth,
int birthyear, float height, float weight);
const std::string &getFirstName() const;
void setFirstName(const std::string &firstName);
const std::string &getLastName() const;
void setLastName(const std::string &lastName);
const Date &getBirthdate() const;
void setBirthdate(const Date &birthdate);
float getHeight() const;
void setHeight(float height);
float getWeight() const;
void setWeight(float weight);
std::string toString()const;
};
}
#endif
Date.cpp:
#include "Date.h"
#include "DateException.h"
#include <sstream>
namespace CIST2362 {
Date::Date() {
//create default constructer
setNames();
setDay(0);
setMonth(0);
setYear(1900);
}
Date::Date(int m, int d, int y) {
//create constructer
setNames();
setDay(d);
setMonth(m);
setYear(y);
}
void Date::setNames() {
names[1] = "January";
names[2] = "Febraury";
names[3] = "March";
names[4] = "April";
names[5] = "May";
names[6] = "June";
names[7] = "July";
names[8] = "August";
names[9] = "September";
names[10] = "October";
names[11] = "November";
names[12] = "December";
}
void Date::setMonth(int m) {
// try if months are less than 0 or greater than 12
try{
if(m<0){
InvalidMonth w;
throw w;
}else{
month=m;
}
}
// catch error
catch(std::exception& e) {
std::cout<<e.what();
}
}
void Date::setDay(int d) {
// try if days are less than 0 or greater than 31
try{
if(d<0){
// throws char
InvalidDay w;
throw w;
}else{
day=d;
}
}
// catch error
catch(std::exception& e) {
std::cout<<e.what();
}
}
void Date::setYear(int y) {
// try if years are less than 0
try{
if(y<0){
// throws char
InvalidYear w;
throw w;
}else{
year=y;
}
}
// catch error
catch(std::exception& e) {
std::cout<<e.what();
}
}
std::string Date::getDateShort() {
//declares stringstream varablies
std::stringstream dd, mm, yy;
//turns day, mouth, year it
dd<<day;
mm<<month;
yy<<year;
//gets dd, mm, yy
std::string s=mm.str()+"/"+dd.str()+"/"+yy.str();
return s;
}
std::string Date::getDateLong()const{
//declares stringstream varablies
std::stringstream dd, mm, yy;
//gets dd, mm, yy
dd<<day;
mm<<month;
yy<<year;
//converts mm, to string
std::string s=names[month]+" "+dd.str()+", "+yy.str();
return s;
}
}
DateException.cpp:
#ifndef LESSON_5_PROGRAMMING_ASSIGNMENT_DATE_H
#define LESSON_5_PROGRAMMING_ASSIGNMENT_DATE_H
#include <iostream>
#include <string>
namespace CIST2362 {
// Constants
const int NUM_MONTHS = 13;
class Date {
private:
int month;
int day;
int year;
// An array of strings to hold
// the names of the months
std::string names[NUM_MONTHS];
// Private member function to assign
// the month names to the names array
void setNames();
public:
// Constructors
Date();
Date(int, int, int);
// Mutators
void setMonth(int m);
void setDay(int d);
void setYear(int y);
// Functions to print the date
std::string getDateShort();
std::string getDateLong()const;
};
}
#endif
`
**DateException.h**
`#ifndef LESSON_5_PROGRAMMING_ASSIGNMENT_DATEEXCEPTION_H
#define LESSON_5_PROGRAMMING_ASSIGNMENT_DATEEXCEPTION_H
#include <exception>
namespace CIST2362 {
// Exception classes
class InvalidDay: public std::exception {
public:
// calls exception error function
const char * what() const throw();
};
class InvalidMonth: public std::exception {
public:
// calls exception error function
const char * what() const throw() ;
};
class InvalidYear: public std::exception {
public:
// calls exception error function
const char * what() const throw();
};
}
#endif
PersonExceptions.cpp:
#include "PersonExceptions.h"
namespace CIST2362 {
const char * badHeight::what() const throw() {
// catchs char and gives exception error
return "Invalid Height assigned - must be a positive number\n";
}
// catchs char and gives exception error
const char * badWeight::what() const throw(){
return "Invalid Weight assigned - must be a positive number\n";
}
}
`
`#include "PersonExceptions.h"
namespace CIST2362 {
const char * badHeight::what() const throw() {
// catchs char and gives exception error
return "Invalid Height assigned - must be a positive number\n";
}
// catchs char and gives exception error
const char * badWeight::what() const throw(){
return "Invalid Weight assigned - must be a positive number\n";
}
}
`
**PersonExceptions.h**
`#ifndef LESSON_5_PROGRAMMING_ASSIGNMENT_PERSONEXCEPTIONS_H
#define LESSON_5_PROGRAMMING_ASSIGNMENT_PERSONEXCEPTIONS_H
#include <exception>
namespace CIST2362 {
class badHeight: public std::exception {
public:
// calls exception error function
const char * what() const throw() ;
};
class badWeight: public std::exception {
public:
// calls exception error function
const char * what() const throw() ;
};
}
#endif
You must catch the exception properly
That's what you are not doing, this is your code
void Person::setHeight(float height) {
// try if height are less than 0
try {
if (height<0) {
badHeight w;
throw w;
}
else {
this->height = height;
}
}
catch (std::exception& e) {
std::cout<<e.what();
}
}
You throw and catch the exception in the setWeight method. Instead you should throw the exception in setWeight (that's where the error occurs) and catch the exception where you want to recover from the error. In your case that would be just before you ask the user for more input.
So change the above code to this
void Person::setHeight(float height) {
if (height<0) {
badHeight w;
throw w;
}
else {
this->height = height;
}
}
In this version you just throw the error, there is no catch because this code has no idea how you want to recover from the error.
And change your main loop to this
// You must catch exceptions properly
while (toupper(answer) == 'Y') {
std::cin >> firstName;
std::cin >> lastName;
std::cin >> birthMonth;
std::cin >> birthDay;
std::cin >> birthYear;
std::cin >> weight;
std::cin >> height;
// place person objects into vector UNLESS AN EXCEPTION OCCURS
try {
CIST2362::Person data(firstName, lastName, birthDay,
birthMonth, birthYear, height, weight);
personDatabase.push_back(data);
}
catch (std::exception& e) {
std::cout << e.what() << '\n';
}
std::cin >> answer;
}
This is where you catch, notice that this way if an exception is thrown then nothing gets added to the person database, so you won't print out the bad entries.

Passing c-strings to class function (assigning it to class member)

I have a class called Person:
class Person {
private:
char name[50];
unsigned int number;
public:
void set_data(const char *newname, unsigned int number) {
*name= *newname; //THE MAIN PROBLEM I WANT TO SOLVE
this->number = number;
}
char* get_name() {
return this->name;
}
unsigned int get_number() {
return this->number;
}
};
I have arrays:
const char *names[] = {"Mark", "Pavel", "Bill", "Jasur", "Jeff"};
int phones[] = { 1234567890, 9876543210, 123321456654, 1998946848479, 1234554321 };
I'm using for loop to set Person members:
Person p;
for (int i = 0; i < 5; i++) {
p.set_data(names[i], phones[i]);
cout << p.get_name() << endl;
}
When I run this, I'm getting wrong output.
Using * the way you are, you are only copying the 1st char into name. You are also not null-terminating name either, which is required by the overloaded operator<< that takes a char* as input.
To copy the entire string, you need to use std::strcpy() (or better, std::strncpy()) instead, eg:
#include <cstring>
void set_data(const char *newname, unsigned int newnumber) {
//std::strcpy(name, newname);
std::strncpy(name, newname, 49);
name[49] = '\0';
number = newnumber;
}
However, since this is C++ and not C, you really should be using std::string instead:
#include <string>
class Person {
private:
std::string name;
unsigned int number;
public:
void set_data(const std::string &newname, unsigned int newnumber) {
name = newname;
number = newnumber;
}
std::string get_name() const {
return name;
}
/* or:
const std::string& get_name() const {
return name;
}
*/
unsigned int get_number() const {
return number;
}
};

How do I return an average of a number of vector objects? C++

Hi I'm quite new to c++ and I have a project but to do but a question in the project requires me to add a function, getAverageCostPerDay(), which takes a vector of Reservations object and returns the average cost of a car reservation. How do I got about doing this? Thanks
Reservation.h
#pragma once
#include <string>
class Reservation
{
private:
int id;
std::string name;
int stDate;
int stMonth;
int stYear;
int duration;
float cost;
std::string licensePlate;
static int reservationCount;
public:
//Constructor
Reservation();
Reservation(int id, std::string name, int stDate, int stMonth, int
stYear, int duration, float cost, std::string licensePlate);
//Destructor
~Reservation();
//Getters
int getId();
std::string getName();
int getStDate();
int getStMonth();
int getStYear();
int getDuration();
float getCost();
std::string getLicensePlate();
//Setters
void setId(int id);
void setName(std::string name);
void setStDate(int stDate);
void setStMonth(int stMonth);
void setStYear(int stYear);
void setDuration(int duration);
void setCost(float cost);
void setLicensePlate(std::string licensePlate);
static int getReservationCount()
{
return reservationCount;
}
};
Reservation.cpp
#include "pch.h"
#include "Reservation.h"
int Reservation::reservationCount = 0;
//Constructor
Reservation::Reservation()
{
this->id = 0;
this->name = "";
this->stDate = 0;
this->stMonth = 0;
this->stYear = 0;
this->duration = 0;
this->cost = 0;
this->licensePlate = "";
reservationCount++;
}
Reservation::Reservation(int id, std::string name, int stDate, int stMonth,
int stYear, int duration, float cost, std::string licensePlate)
{
this->id = id;
this->name = name;
this->stDate = stDate;
this->stMonth = stMonth;
this->stYear = stYear;
this->duration = duration;
this->cost = cost;
this->licensePlate = licensePlate;
reservationCount++;
}
//Destructor
Reservation::~Reservation()
{
reservationCount--;
std::cout << "Destroying (" << this->name << ")" << std::endl;
}
//Getters
int Reservation::getId()
{
return this->id;
}
std::string Reservation::getName()
{
return this->name;
}
int Reservation::getStDate()
{
return this->stDate;
}
int Reservation::getStMonth()
{
return this->stMonth;
}
int Reservation::getStYear()
{
return this->stYear;
}
int Reservation::getDuration()
{
return this->duration;
}
float Reservation::getCost()
{
return this->cost;
}
std::string Reservation::getLicensePlate()
{
return this->licensePlate;
}
//Setters
void Reservation::setId(int id)
{
this->id = id;
}
void Reservation::setName(std::string name)
{
this->name = name;
}
void Reservation::setStDate(int stDate)
{
this->stDate = stDate;
}
void Reservation::setStMonth(int stMonth)
{
this->stMonth = stMonth;
}
void Reservation::setStYear(int stYear)
{
this->stYear = stYear;
}
void Reservation::setDuration(int duration)
{
this->duration = duration;
}
void Reservation::setCost(float cost)
{
this->cost = cost;
}
void Reservation::setLicensePlate(std::string licensePlate)
{
this->licensePlate = licensePlate;
}
Main.cpp
#include "pch.h"
#include "Reservation.h"
//Regular Expressions
std::string idRegexStr = "[0-9]{3,4}";
std::string nameRegexStr = "[A-Za-z]{1}[a-z]{1,30} [A-Za-z]{1}[a-z]{1,30}";
std::string stDateRegexStr = "[0-3]{1}[0-9]{1}";
std::string stMonthRegexStr = "[0-1]{1}[0-9]{1}";
std::string stYearRegexStr = "[1-2]{1}[0-9]{1}[0-9]{1}[0-9]{1}";
std::string durationRegexStr = "[1-9]{1}[0-9]{1}";
std::string costRegexStr = "[0-9]{2}.[0-9]{2}";
std::string licencePlateRegexStr = "[0-9]{2,3}\\s*[A-Z]{2,3}\\s*[0-9]+";
//Validates data against a user-defined string
bool validate(std::string regexStr, std::string data)
{
return std::regex_match(data, std::regex(regexStr));
}
std::vector<Reservation>populateVector(Reservation defaultVector, int size)
{
std::vector<Reservation> outVector;
for (int i = 0; i < size; i++)
{
outVector.push_back(defaultVector);
}
return outVector;
}
double getAverageCostPerDay(const std::vector<Reservation> outVector)
{
double average = 0;
for (std::size_t i = 0; i < outVector.size(); i++)
{
average = std::vector<Reservation>outVector.at(float cost);
}
return true;
}
int main()
{
/*
//these were example values to see if regex works
bool idIsValid = validate(idRegexStr, "101");
bool nameIsValid = validate(nameRegexStr, "John Smith");
bool stDateIsValid = validate(stDateRegexStr, "24");
bool stMonthIsValid = validate(stMonthRegexStr, "10");
bool stYearIsValid = validate(stYearRegexStr, "2018");
bool durationIsValid = validate(durationRegexStr, "10");
bool costIsValid = validate(costRegexStr, "22.50");
bool licenseIsValid = validate(licencePlateRegexStr, "181 LH 555");
std::cout << "Invalid = 0 / Valid = 1\n";
std::cout << "\n";
std::cout << "Valid ID: " << idIsValid << std::endl;
std::cout << "Valid Name: " << nameIsValid << std::endl;
std::cout << "Valid Start Date: " << stDateIsValid << std::endl;
std::cout << "Valid Start Month: " << stMonthIsValid << std::endl;
std::cout << "Valid Start Year: " << stYearIsValid << std::endl;
std::cout << "Valid Duration: " << durationIsValid << std::endl;
std::cout << "Valid Cost: " << costIsValid << std::endl;
std::cout << "Valid License: " << licenseIsValid << std::endl;
*/
Reservation r1(101, "John Smith", 24, 10, 2018, 4, 22.50, "181 LH
5555");
Reservation r2(102, "Jane Caroll", 31, 01, 2017, 6, 34.25, "161 DUB
55454");
Reservation r3(103, "Sean Morrissey", 16, 06, 2014, 2, 67.50, "162 WEX
83675");
Reservation r4(104, "Billy Joe", 04, 03, 2016, 8, 51.20, "152 DUB
10347");
std::cout << "Reservation Count: " << Reservation::getReservationCount()
<<
std::endl;
}
There are a couple of ways to do this.
You could wrap your vector of reservations inside of a class and keep track of how many there are, what the total cost is, and calculate the average.
However, if you have to return this information through the Reservation class, then you'll have to use a static variable for sum of costs and number of reservation objects. Static attributes are available in all objects of that class and will have the same value between all objects. So, every time you create a Reservation object, increment the count and sum of costs. Then when you need the average, you can calculate it from any of the objects or through the class (if you make a static function to do this).

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

cannot swap objects in an array in C++

i am new to C++ and stuck in the swap stuff
the code below is a program of sort employee names in alphbetical order and print out the orginal one and sorted one ,but the
swap method doesn't work
the two output of printEmployees is excatly the same, can anyone help me? thx
#include <iostream>
#include <string>
#include <iomanip>
#include <algorithm>
using namespace std;
class employee
{
/* Employee class to contain employee data
*/
private:
string surname;
double hourlyRate;
int empNumber;
public:
employee() {
hourlyRate = -1;
empNumber = -1;
surname = "";
}
employee(const employee &other) :
surname(other.surname),
hourlyRate(other.hourlyRate),
empNumber(other.empNumber){}
void setEmployee(const string &name, double rate,int num);
string getSurname() const;
void printEmployee() const;
employee& operator = (const employee &other)
{employee temp(other);
return *this;}};
void employee::setEmployee(const string &name, double rate, int num) {
surname = name;
hourlyRate = rate;
empNumber = num;
}
string employee::getSurname() const { return surname; }
void employee::printEmployee() const {
cout << fixed;
cout << setw(20) << surname << setw(4) << empNumber << " " << hourlyRate << "\n";
}
void printEmployees(employee employees[], int number)
{
int i;
for (i=0; i<number; i++) { employees[i].printEmployee(); }
cout << "\n";
}
void swap(employee employees[], int a, int b)
{
employee temp(employees[a]);
employees[a] = employees[b];
employees[b] = temp;
}
void sortEmployees(employee employees[], int number)
{
/* use selection sort to order employees,
in employee
name order
*/
int inner, outer, max;
for (outer=number-1; outer>0; outer--)
{
// run though array number of times
max = 0;
for (inner=1;
inner<=outer; inner++)
{
// find alphabeticaly largest surname in section of array
if (employees
[inner].getSurname() < employees[max].getSurname())
max = inner;
}
if (max != outer)
{
//
swap largest with last element looked at in array
swap(employees, max, outer);
}
}
}
int main()
{
employee employees[5];
employees[0].setEmployee("Stone", 35.75, 053);
employees[1].setEmployee
("Rubble", 12, 163);
employees[2].setEmployee("Flintstone", 15.75, 97);
employees[3].setEmployee("Pebble", 10.25, 104);
employees[4].setEmployee("Rockwall", 22.75, 15);
printEmployees(employees, 5);
sortEmployees(employees,5);
printEmployees(employees, 5);
return 0;
}
This code is broken:
employee& operator = (const employee &other)
{employee temp(other);
return *this;}
It should be something like:
employee& operator= (const employee &other)
{
surname = other.surname;
hourlyRate = other.hourlyRate;
empNumber = other.empNumber;
return *this;
}
As told by others, fixing your assignment operator will solve the problem.
I see that you tried to implement operator= in terms of copy constructor but missed to do a swap. You can try the below approach if you want to avoid code duplication in your copy constructor and assignment operator.
employee& operator=(const employee& other)
{
employee temp(other);
swap(temp);
return *this;
}
void swap(employee& other)
{
std::swap(surname, other.surname);
std::swap(hourlyRate, other.hourlyRate);
std::swap(empNumber, other.empNumber);
}